首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

IBM JVM for Linux JIT 诊断简介(4)

IBM JVM for Linux JIT 诊断简介(4)

如何发现失败的方法?设置 JITC_COMPILEOPT=COMPILING,并再次运行您的程序。在设置这个选项之后,JIT 编译器会在对方法进行编译时为每个方法打印两条消息。例如:
1
2
Compiling {java/lang/MyClass}{MyMethod}
0x0BF025C0 {java/lang/MyClass}{MyMethod}




第一条消息 Compiling {java/lang/MyClass}{MyMethod} 说明 JIT 编译器已经开始编译这个方法了。第二条消息说明编译过程已经完成了,十六进制的地址表示每次调用这个方法时,所执行的机器代码的起始偏移量。
如果您看到如下格式的一条消息,其中“F”表示这个方法没有被编译成功。
1
Compiling   F   {package/class}{method}




如果您怀疑会失败的方法的名字右边有一个“X”,那么这个“X”就表示发生了一次 MMI2JIT 转换,其中在检测到循环时对这个方法进行了编译,在一次调用这个方法时,对该方法的执行方式从解释(MMI)模式切换到了编译(JIT)模式。例如:
1
Compiling {java/util/MyClasss}{MyMethod} X




有三种可能的情景可以查找除程序输出之外的最后一条消息:
  • 0x012345678 {package/class}{method}:崩溃是在执行一个已编译的方法(不一定是这条消息列出的方法)时发生的 。
  • 该程序继续运行,但是性能降低了,或者需要花费更多时间来判断崩溃之前哪一条是最后的消息了。
  • Compiling {package/class}{method}:崩溃是在编译过程中发生的。
在第一种情况下,可能的原因是 JIT 编译器会为一个方法产生已编译的代码,这个已编译的代码会产生一个错误。您也许可以通过检查错误发生处的地址来判断是哪个方法导致了这个错误的发生。
如果您可以获得一个错误指令地址,请遵循以下步骤来隔离失效的方法:
  • 将 COMPILING 选项修改为 COMPILING(verbose)。这将会导致在输出结果中包含每个方法已编译的代码的起始地址和结束地址。如果您已经将 COMPILING 选项的范围缩小到一个类/方法规范中,请使用 COMPILING(verbose){class-spec}{method-spec}。
  • 再次运行这个程序,但是要将标准输出重定向到一个文件中,例如:
    1
    java -options classname >compiling.log




  • 当错误发生时,使用 gdb 调试器来寻找错误地址,这取决于您的操作系统(您需要重复这次调用过程,因为两次调用时失败的地址可能会不同)。
    • 在产生 core 文件的目录中启动 gdb 调试器:
      1
      gdb java core




    • 如果 gdb 调试器可以读取 core 文件,它就可以分析出失效发生的地址(例如,Segmentation fault in function_name at 0x10001234)。
    • 要获得一个堆栈跟踪信息,可以使用 bt 命令:
      1
      (gdb) bt




    • 然后使用 quit 命令退出 gdb。
    确保 core 文件的大小(这可以在 ulimit -c 命令的结果中看到)没有被设置为 0 或设置得太小,因为在前一种情况下,不会产生 core 文件,而在后一种情况下,core 文件可能会被截断。
  • 在 compiling.log 文件中查找一个函数的开始地址和结束地址,它是十六进制的形式,其间就包含着错误地址。注意开始的十六进制地址通常是以升序排列的,但这并不是必须的。
  • 如果您找到一个函数地址范围包含了失败的指令地址,那么这个范围的消息就会说明可能引入错误的方法。在第二种情况下,错误指令是未知的,因此需要使用其他技术来缩小出错类/方法对的范围:
    • 如果在程序崩溃之前打印(或者写到 javacore.txt)了 Java 堆栈跟踪,就检查它。在堆栈跟踪信息顶部列出的方法就是主要的候选者。
    • 如果您可以访问源代码,请在所怀疑的 Java 方法中插入一些指示性的代码,注意哪些怀疑的代码没有启动,或者没有完成。在有些情况下,在所怀疑的方法中添加一个 System.out.println() 语句可能会导致问题的消失,因为字节码和最终为该方法编译后的代码可能会发生很多变化,从而改变对该方法所应用的优化流程。在这种情况下,把出现 println() 的方法看作被怀疑的方法。如果您在很多怀疑的方法中都插入一个 println() 调用,则尽量删除 println() 调用,直到您确定哪一个防止了失败的出现;包含 println() 调用的方法很可能就是值得怀疑的地方。
    • 使用 libjitc.so 的调试版本 —— libjitc_g.so。
调试版本的 JIT 库包含对 C 库函数中的 assert() 函数的调用。这些调用被放到 JIT 编译器的代码中,用来断言所需要的条件为真;当一个 assert 调用失败时,就说明 JIT 编译器代码碰到了非预期的情况。通常一个断言失效都是在编译一个失败方法时发生的,然而在使用非调试版本的 JIT 库时,失败情况可能要到编译方法中的一个特定指令在以后实际执行时才会出现。当使用调试版本的 JIT 库时,您的程序会更可能在打印问题方法的 Compiling 消息之后失败。
调试版本的可执行程序和共享库包含在 JDK 中,但没有包含在 JRE 中。
要使用调试版本的 JIT 库,请遵循以下步骤:
  • 检查在 java 命令的  -Dsun.boot.library.path  选项中所指向的一个目录中存在所需要的调试库。检查存在共享库 libjitc_g.so。
  • 在调用 java 命令之前,设置环境变量:JAVA_COMPILER=jitcg。
如果您看到下面的消息:
1
Warning: JIT compiler "jitcg" not found. Will use interpreter





请检查所指定的库路径(-Dsun.boot.library.path)是正确的,所指定的调试库在这个路径中的一个目录中的确存在。
当您运行这个版本的 JVM 时,如果碰到断言失败的情况,执行过程就会停止,同时会显示一条断言失败消息。
在第三种情况下,或者在方法编译失败时,您会看到:
1
Compiling   F   {package/class}{method}





您可以跳过有问题的方法,不对其使用 JIT 进行编译。
您可以使用 JITC_COMPILEOPT 变量的 SKIP 选项禁用对失败方法进行 JIT 编译。
例如:
JITC_COMPILEOPT=SKIP{failingPackage/failingClass}{failingMethod}跳过对特定类中的特定方法进行 JIT 编译的过程JITC_COMPILEOPT=SKIP{failingPackage/failingClass}{*}跳过对一个类的所有方法进行 JIT 编译的过程JITC_COMPILEOPT=SKIP{failingPackage/*}{*}这可以跳过对失败包中所有类的所有方法进行 JIT 编译的过程如果上面其他查找失效方法的技术都失败了,那么这种相同的跳过一些方法的技术可以应用到更广泛的范围,作为一种强制方法来隔离失败的方法,或者一个失败方法的集合。
JITC_COMPILEOPT 变量在 Linux 以及其他平台上允许使用多个以点号(.)分隔开的选项,以及在正则表达式中使用通配符。例如:
JITC_COMPILEOPT=COMPILING:SKIP{com/class1/*}{*}{com /class2/*}{*}跳过 JIT 对 firm.empdata 和 ourfirm.orderentry 包中所有类的所有方法的编译,按照“COMPILING”选项的定义打印 JIT 编译的信息。JITC_COMPILEOPT=SKIP{myClass?2}{myfunc?b} 跳过名为 myClass?2 的任何类中的名为 myfunc?b 的所有方法,其中 ? 是任意的单个字符。JITC_COMPILEOPT=SKIP{[ab]?[de]*}{*} 跳过第一个字母为“a”或“b”,第三个字母为“d”或“e”的所有类中的所有方法。 布尔 OR 和 NOT 操作分别是 | 和 ^ 操作符。注意这些字符在某些命令 shell 中具有特殊的意义,需要使用转义字符或引号。
JITC_COMPILEOPT=SKIP{java*|sun*}{*} 跳过以 java 或 sun 开始的所有类的所有方法。JITC_COMPILEOPT=SKIP{^[js]*}{*}跳过除了以“j”和“s”开头的所有类的所有方法。在这个过程的最后,您应该可以提炼一组范围有限的方法集合,或者理想地说,甚至是提炼出一个方法,这样在为这个方法或这个范围很小的方法集合禁用所有的 JIT 优化选项时可以解决问题。
返回列表