IBM JVM for Linux JIT 诊断简介(2)
- UID
- 1066743
|
IBM JVM for Linux JIT 诊断简介(2)
JIT 诊断本节将介绍在问题发生时用来调试和诊断 IBM JVM 的 JIT 和 MMI 的技术。上一节简要介绍了 JIT,它是 IBM JVM 的一个基本部分。
在任何给定的时刻,JVM 进程包含一些可执行文件和一些使用 JIT 编译的代码,它们被动态链接到 JVM 中的 MMI 方法的封装程序上。JIT 编译的本地机器代码被放置到 JVM 本地数据内存段中,这样就可以增加 JVM 进程的本地内存占用,并且 MMI 封装程序被修改为指向编译后的代码。
因此,JIT 对于 Java 程序的执行流程会产生很大的影响。
在将程序从一个平台上迁移到另外一个平台上碰到的问题如下:
- 死锁挂起
- 一直产生不正确的结果
- 结果不一致
- 不正常结束
- 无限循环
- 内存泄漏
对问题原因要考虑的第一件事情是 JIT。
尽快在判断问题原因时,确定 JIT 是否是问题的根源非常重要,这是由于 3 个原因:
- 问题可能是由于 JIT 在 JVM 中给定的活动角色而引起的。
- JIT 调试与其他类型的问题判断技术有很大的不同。
- JIT 调试过程可能会非常耗费时间,而且非常复杂,通常需要高级的专门技术。
确定是否是 JIT 问题在某些情况下,从问题的特性可以很清楚地看出就是 JIT 的问题。例如,在 JVM 终止时带有 Javadump(在 Linux 上,Javadump 的文件名的格式为 javacore.YYYYMMDD.HHMMSS.PID.txt )或 Linux core 文件的情况下,从 Javadump 中的跟踪信息或 gdb 对 Java 可执行文件和 core 文件的输出信息中,可以很清楚地判断出 JIT 就是产生问题的原因。在某些情况下,会直接显示导致 JVM 进程死亡的信号是在 libjitc.so 中接收到的。在另外一些情况下,在 JVM 进程的代码中,但是在该进程的已编译代码之外,会产生崩溃或挂起,这可以说明问题是由于 JIT 编译的代码产生的。
然而,在大部分情况下,并没有清晰的迹象表明 JIT 是否是问题的源头。因此,给定 JIT 的重要性后,在问题判断过程中的第一个步骤应该是禁用 JIT,除非这显然不是一个与 JIT 相关的问题。即使在有迹象表明 JIT 就是问题的原因的情况下,最好也通过禁用 JIT 进行一下验证,并重新运行一下禁用了 JIT 的程序。
要禁用 JIT,首先请检查一下当前环境变量 JAVA_COMPILER 的设置,然后将其设置为 NONE。例如,对于 Bourne Again Shell (bash)或 Korn shell(ksh),设置如下:
1
| export JAVA_COMPILER=NONE
|
对于 csh,设置如下:
1
| setenv JAVA_COMPILER NONE
|
另外一种禁用 JIT 的方法是向 java 命令传递 -D 参数,将 java.compiler 设置为 NONE,从而覆盖默认的环境变量置:
1
| java -Djava.compiler=NONE <myapp>
|
JIT 默认是被启用的。要验证 JIT 是否被启用了,可以使用 java 命令的 -version 选项:
如果没有启用 JIT,就会显示一个包含如下内容的消息:
如果启用了 JIT,就会显示一个包含如下内容的消息:
如果指定了 JAVA_COMPILER="" 或 -Djava.compiler="",那就禁用了 JIT。如果 JAVA_COMPILER 没有设置,如下:
那么 JIT 编译器就启用了。
再次运行一下程序,看一下禁用 JIT 之后问题是否重现。如果问题可以重现,那么这就不是一个与 JIT 有关的问题。如果在禁用 JIT 之后问题就不存在了,那么这就可能是一个与 JIT 有关的问题。在禁用 JIT 之后问题就不再出现的现象并不意味着 JIT 编译器就是问题的原因。例如,高度线程化且时间相关的程序中的方法在编译后和解释时的运行速度可能会不同,因此 Java 代码中的逻辑错误只会在编译代码之后才会出现。
要启用 JIT,请将 JAVA_COMPILER 设置为 jitc,或者使用下面的命令行来切换 JIT 编译器:
1
| java -Djava.compiler=jitc <myapp>
|
或者取消 JAVA_COMPILER 环境变量的设置,或者从传递给 java 命令的选项中删除 -Djava.compiler 选项。 |
|
|
|
|
|