用 Javadump 解决问题
使用 Javadump 提供的信息,可以确定系统中存在哪些类装入器。这包括任何用户自定义的类装入器。从装入的类列表中,可以找出特定的类是由哪个类装入器装入的。如果找不到某个类,说明系统中的任何一个类装入器都没有装入它(通常会形成 ClassNotFoundException 异常)。
可以用 Javadump 诊断的其他类型的问题包括:
- 类装入器命名空间问题。 类装入器的命名空间是类装入器和它装入的所有类的组合。例如,如果某个类存在,但是由错误的类装入器装入(有时会造成
NoClassDefFoundError 异常),那么命名空间就是错误的 —— 也就是说,类在错误的类路径中。为了纠正这种问题,可以试着把类放到不同的位置(例如放在正常的 Java 类路径中),并确保由系统类装入器装入它。
- 类装入器约束问题。 在这个系列的最后一篇文章中将讨论这种问题的一个示例。
Java 方法跟踪
IBM JVM 有一个内置的方法跟踪工具。这样,不需要修改 Java 代码,就可以跟踪任何 Java 代码(包括核心系统)中的方法。因为这个工具可以提供大量数据,所以可以控制跟踪的级别,只获取需要的信息。
启动跟踪的选项取决于 JVM 的发行版。关于这些选项的细节,请参阅 IBM Diagnostics Guides(请参阅 参考资料 中的链接)。
下面是一些命令行示例:
在 IBM Java 1.4.2 中运行 HelloWorld 时要跟踪所有 java.lang.ClassLoader:
java -Dibm.dg.trc.methods=java/lang/ClassLoader.*() -Dibm.dg.trc.print=mt HelloWorld
|
跟踪 ClassLoader 中的 loadClass() 方法和 HelloWorld 中的方法,也在 IBM Java 1.4.2 中:
java -Dibm.dg.trc.methods=java/lang/ClassLoader.loadClass(),HelloWorld.*()
-Dibm.dg.trc.print=mt HelloWorld
|
解释方法跟踪的输出
这里 是方法跟踪输出的一个示例(用前面一段的第二个命令行)。
跟踪的每一行都提供了比上面显示的更多的信息。我们来完整地看看上面的一行:
12:57:41.277 0x002A23C0 04000D > java/lang/ClassLoader.loadClass Bytecode method,
This = 0x00D2B830, Signature: (Ljava/lang/String;Z)Ljava
/lang/Class;
|
这个跟踪包括:
12:57:41.277:方法进入或退出的时间戳。
0x002A23C0:线程 ID。
04000D:某些高级诊断使用的内部 JVM 跟踪点。
- 余下的信息显示是进入(
>)还是退出了(<)方法,后面跟着方法的细节。
用方法跟踪解决问题
可以用方法跟踪解决不同类型的问题,包括:
- 性能热点: 使用时间戳,可以发现需要花费相当多时间来执行的方法。
- 挂起: 最后的方法项通常是很好的线索,可以指明应用程序是否挂起。
- 错误对象: 使用地址,通过与对象的构建函数调用的地址进行比对,可以检查出是不是在正确的对象上调用方法 。
- 意外的代码路径: 通过跟踪进入和退出点,可以看出程序是否采用了意外的代码路径。
- 其他错误: 最后的方法项是对错误发生位置的良好提示。