如何在JDI中调试由自定义类加载器加载的类

时间:2017-06-26 03:00:44

标签: java jdi jpda

使用参数-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);

我该怎么办?

1 个答案:

答案 0 :(得分:1)

监控JDI中的类加载 在过去的几周里,我一直在构建基于Java调试接口的Java进程监控工具。虽然我之前做了很多这方面的工作,但已经有几年了,所以现在我正在回顾我的步骤。当我记得细节和陷阱时,我一直在发表我的笔记,希望你能发现它们有用。

今天我稍后将讨论ClassPrepareEvents。您可能已经知道,您可以将调试器附加到已经运行的Java进程,或者从调试器启动目标进程(使用各种命令行开关)。在我的项目中,我总是将附加到正在运行的流程,因为重点是根据需要收集流程数据。 JDI的ClassPrepareEvent之所以引人注目,是因为当你启动一个调试目标进程时,或者当你附加到一个已经运行的进程时,你所希望的一些断点很可能存在于尚未加载。

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

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

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

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

最后,我之前没有看过的一个问题(无论是针对此开发工作,还是我之前在此领域的开发) - 卸载类时会发生什么,尤其是已注册断点请求的类。例如,注册的断点请求是否会阻止类被卸载?如果班级没有加载,你是否关心搁浅的断点请求? (答案:是的,我想,如果它被重新加载,你不再有一个有效的断点请求)。 JDI确实有一个ClassUnloadEvent,您也可以为其注册一个监听器。正如我所说的那样,我没有处理过这个(可能的)问题,以前从未见过目标类被卸载过,但是知道它是一个很好的问题&#34;那里有一个API&#34; 。 Follow link for more details