2

使用参数 -Xdebug, -agentlib:jdwp=transport=dt_socket, server=y, suspend=n, address=4404 启动目标程序。

使用 com.sun.jdi 相关类调试目标程序。VirtualMachine 类的 classesByName 方法。自定义类加载器加载的类不可用。

在目标中,我可以通过

Class.forName("Script1", false, clazz.getClassLoader())

在 VirtualMachine 类中,只有方法:

List<ReferenceType> classesByName(String var1);

我应该怎么做?

4

1 回答 1

1

监控 JDI 中的类加载 在过去的几周里,我一直在构建一个基于 Java 调试接口的 Java 进程监控工具。虽然我以前做过很多这样的工作,但已经有几年了,所以现在我正在重蹈覆辙。当我记得细节和陷阱时,我一直在发布我的笔记,希望你会发现它们有用。

今天我要讲讲ClassPrepareEvents,在了解一些背景知识之后。您可能已经知道,您可以将调试器附加到已经运行的 Java 进程,或从调试器启动目标进程本身(使用各种命令行开关)。在我的项目中,我总是会附加到正在运行的进程,因为关键是根据需要收集进程数据。JDI 的 ClassPrepareEvent 有趣的原因在于,当您启动调试目标进程时,或者甚至当您附加到已经运行的进程时,您想要的一些断点很可能位于尚未加载的类中。

在我通常的场景中,我调用 com.sun.jdi.VirtualMachine 的 allClasses() 方法来获取所有加载的 ReferenceTypes 的列表。一种将 ReferenceType 视为 Java 类定义的方法。如果您的 Java 类有内部类,那么 JDI 会将它们分解为单独的 ReferenceType。每个 ReferenceType 都包含一个行位置集合;这些对应于可以设置断点的代码行,并由(除其他外)源代码行号标识。如果一行源代码不能成为断点的目标,那么在 ReferenceType 中将不会有它的行位置。在我基于调试器的应用程序中,我逐步检查所有 ReferenceType 的行位置,将行位置与断点规范匹配,然后注册我的断点请求。

你可以猜到,我有一个潜在的问题:如果我需要的类在我构建断点请求的时候还没有加载,我该怎么办?答案是:JDI 的 ClassPrepareEvent。使用这部分 API 的入口点是 EventRequestManager 的 createClassPrepareRequest() 方法。提出请求后,我们用来等待断点事件的事件监听器循环也可用于等待类准备事件(请参阅 JVM 规范以了解类准备的定义)。

我记得我之前开发这个 API 的一件事是这里存在时间风险。您可能希望在遍历当前加载的类列表之前创建类准备请求。原因是您不想落入这个陷阱:迭代一组当前加载的类,处理并发出断点请求。突然,一个你需要的类被加载了!您注册了 class-prepare 事件并在加载类时开始获取事件,但是您错过了在步骤 #1 和步骤 #3 之间加载的类。这是另一个可能的陷阱:注册类准备事件,这样您就不会被上述问题所困扰。遍历当前加载的类,根据需要请求断点。处理新加载的类,根据需要请求断点。第二种方法的问题是您可能会处理相同的断点两次。为什么?当您遍历当前加载的类时,该列表中的某些类很可能是已出现在您的类准备侦听器中的类。这些问题都不能通过在某处使用同步关键字来解决。

无论您是从调试器启动目标应用程序还是事后附加到它,您都必须处理此问题的一些变化。我处理它的方式是向我用来定义每个断点规范的类添加一些状态。当找到每个相应的加载类并发出断点请求时,我在规范上设置了一个标志,以便我知道请求已注册。此外,我遵循上面概述的第二种方法(最好有重复而不是错过一个)。如果我从 VM 的 ReferenceType 列表中看到我已经处理过的类的类准备事件,那么我只是跳过它。我对相反的情况做同样的事情,其中​​我的 ReferenceTypes 列表包含我刚刚在 ClassPrepareEvent 侦听器中处理的 ReferenceTypes。

最后,一个我以前没有研究过的问题(无论是在这个开发工作中,还是在我之前在这个领域的开发中)——当一个类被卸载时会发生什么,特别是一个你已经注册了断点请求的类。例如,注册的断点请求会阻止类被卸载吗?如果类甚至没有加载,您是否关心搁浅的断点请求?(答案:是的,我想,如果它被重新加载并且您不再有有效的断点请求)。JDI 确实有一个 ClassUnloadEvent,您也可以为它注册一个侦听器。正如我所说,我还没有处理过这个(可能的)问题,以前从未见过目标类被卸载,但很高兴知道“有一个 API”。 点击链接了解更多详情

于 2017-06-26T03:58:17.487 回答