解析JVM和JIT诊断技术的用法

在任何给定的时刻,JVM进程包含一些可执行文件和一些使用JIT编译的代码,它们被动态链接到JVM中的MMI方法的封装程序上。JIT编译的本地机器代码被放置到JVM本地数据内存段中,这样就可以增加JVM进程的本地内存占用,并且MMI封装程序被修改为指向编译后的代码。

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)或Linuxcore文件的情况下,从Javadump中的跟踪信息或gdb对Java可执行文件和core文件的输出信息中,可以很清楚地判断出JIT就是产生问题的原因。在某些情况下,会直接显示导致JVM进程死亡的信号是在libjitc.so中接收到的。在另外一些情况下,在JVM进程的代码中,但是在该进程的已编译代码之外,会产生崩溃或挂起,这可以说明问题是由于JIT编译的代码产生的。

然而,在大部分情况下,并没有清晰的迹象表明JIT是否是问题的源头。因此,给定JIT的重要性后,在问题判断过程中的第一个步骤应该是禁用JIT,除非这显然不是一个与JIT相关的问题。即使在有迹象表明JIT就是问题的原因的情况下,最好也通过禁用JIT进行一下验证,并重新运行一下禁用了JIT的程序。

要禁用JIT,首先请检查一下当前环境变量JAVA_COMPILER的设置,然后将其设置为NONE。例如,对于BourneAgainShell(bash)或Kornshell(ksh),设置如下:exportJAVA_COMPILER=NONE

对于csh,设置如下:

setenvJAVA_COMPILERNONE  


 

另外一种禁用JIT的方法是向java命令传递-D参数,将java.compiler设置为NONE,从而覆盖默认的环境变量置

java-Djava.compiler=NONE<myapp> 


 

JIT默认是被启用的。要验证JIT是否被启用了,可以使用java命令的-version选项:java-version

如果没有启用JIT,就会显示一个包含如下内容的消息:

JITdisabled  


 

如果启用了JIT,就会显示一个包含如下内容的消息:

JITenabled:jitc  


 

如果指定了JAVA_COMPILER=""或-Djava.compiler="",那就禁用了JIT。如果JAVA_COMPILER没有设置,如下:

unsetJAVA_COMPILER  


 

那么JIT编译器就启用了。

再次运行一下程序,看一下禁用JIT之后问题是否重现。如果问题可以重现,那么这就不是一个与JIT有关的问题。如果在禁用JIT之后问题就不存在了,那么这就可能是一个与JIT有关的问题。在禁用JIT之后问题就不再出现的现象并不意味着JIT编译器就是问题的原因。例如,高度线程化且时间相关的程序中的方法在编译后和解释时的运行速度可能会不同,因此Java代码中的逻辑错误只会在编译代码之后才会出现。

要启用JIT,请将JAVA_COMPILER设置为jitc,或者使用下面的命令行来切换JIT编译器:

java-Djava.compiler=jitc<myapp> 


 

jvm

相关推荐