在任何给定的时刻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是否是问题的根源非常重要这是由于个原因 ◆问题可能是由于JIT在JVM中给定的活动角色而引起的 ◆JIT调试与其他类型的问题判断技术有很大的不同 ◆JIT调试过程可能会非常耗费时间而且非常复杂通常需要高级的专门技术 确定是否是JIT问题 在某些情况下从问题的特性可以很清楚地看出就是JIT的问题例如在JVM终止时带有Javadump(在Linux上Javadump的文件名的格式为javacoreYYYYMMDDHHMMSSPIDtxt)或Linuxcore文件的情况下从Javadump中的跟蹤信息或gdb对Java可执行文件和core文件的输出信息中可以很清楚地判断出JIT就是产生问题的原因在某些情况下会直接显示导致JVM进程死亡的信号是在libjitcso中接收到的在另外一些情况下在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参数将piler设置为NONE从而覆盖默认的环境变量置 piler=NONE<myapp> JIT默认是被启用的要验证JIT是否被启用了可以使用java命令的version选项javaversion 如果没有启用JIT就会显示一个包含如下内容的消息 JITdisabled 如果启用了JIT就会显示一个包含如下内容的消息 JITenabled:jitc 如果指定了JAVA_COMPILER=或piler=那就禁用了JIT如果JAVA_COMPILER没有设置如下 unsetJAVA_COMPILER 那么JIT编译器就启用了 再次运行一下程序看一下禁用JIT之后问题是否重现如果问题可以重现那么这就不是一个与JIT有关的问题如果在禁用JIT之后问题就不存在了那么这就可能是一个与JIT有关的问题在禁用JIT之后问题就不再出现的现象并不意味着JIT编译器就是问题的原因例如高度线程化且时间相关的程序中的方法在编译后和解释时的运行速度可能会不同因此Java代码中的逻辑错误只会在编译代码之后才会出现 要启用JIT请将JAVA_COMPILER设置为jitc或者使用下面的命令行来切换JIT编译器 piler=jitc<myapp> 或者取消JAVA_COMPILER环境变量的设置或者从传递给java命令的选项中删除piler选项 |