【问题标题】:How to use -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print option with JVM HotSpot如何在 JVM HotSpot 中使用 -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print 选项
【发布时间】:2012-03-09 14:38:51
【问题描述】:

我正在尝试使用-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod 命令行,如this post 中所述。

看来open-jdk (https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly) 可以使用它。

如何在 oracle JDK7 和 JVM HotSpot 中使用这些选项(或类似选项)?

【问题讨论】:

  • 看起来并不难尝试
  • Ofc 我试过了,但它不起作用,我的问题是如何让它们工作?我会编辑。
  • 您是否尝试过“如果没有输出,请使用 -XX:+PrintCompilation 来验证您的方法是否正在编译。”
  • 是的,它只做一行数字,就像上面的选项一样。顺便说一下,这个文档是针对 openjdk 的。我认为它不适用于 Java HotSpot。我试图找到一个等价物。

标签: java assembly jvm java-7


【解决方案1】:

在我的情况下查看反汇编的编译代码:

$ java -XX:CompileThreshold=1 -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand="compileonly pac/kage/MyClass myMethod" MyClass

在上面的例子中是循环:for (int i = 0; i < 1 000 000; i++) {...}, 这就是为什么在没有 1 000 000 次迭代的情况下,我们需要 -XX:CompileThreshold=1 选项(默认情况下 -server 为 10 000)来查看我们反汇编的编译代码。

【讨论】:

    【解决方案2】:

    这些说明适用于 Linux (Ubuntu 10.04.4 LTS),但应该适用于您的操作系统。下载Oracle JDK 7u3并适当设置JAVA_HOMEPATH环境变量后,执行以下检查可用选项:

    java -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version
    

    您应该会看到UnlockDiagnosticVMOptionsCompileCommandPrintAssembly 选项可用。使用CompileCommand 选项也将启用PrintAssembly 选项。但是,您需要 PrintAssembly 的 HotSpot 反汇编插件才能工作;如果没有它,您可能会看到如下内容:

    $ java -version
    java version "1.7.0_03"
    Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
    Java HotSpot(TM) Server VM (build 22.1-b02, mixed mode)
    $ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main
    CompilerOracle: print *Main.main
    Java HotSpot(TM) Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
    Compiled method (c2)      68    1 %           Main::main @ 4 (49 bytes)
     total in heap  [0xb3a97548,0xb3a979ec] = 1188
     relocation     [0xb3a97610,0xb3a97624] = 20
     main code      [0xb3a97640,0xb3a97840] = 512
     stub code      [0xb3a97840,0xb3a97850] = 16
     oops           [0xb3a97850,0xb3a97858] = 8
     scopes data    [0xb3a97858,0xb3a97898] = 64
     scopes pcs     [0xb3a97898,0xb3a979e8] = 336
     dependencies   [0xb3a979e8,0xb3a979ec] = 4
    Could not load hsdis-i386.so; library not loadable; PrintAssembly is disabled
    OopMapSet contains 1 OopMaps
    

    要获得 HotSpot 反汇编插件,您需要构建它。查看 OpenJDK 7u2 源代码,hsdis plugin readme 说:

    要将插件与 JVM 一起使用,您需要一个可以加载它的新版本。 如果你的 JVM 的产品模式不接受 -XX:+PrintAssembly, 您没有足够新的版本。

    要构建这个项目,您 [需要] 一份 GNU binutils 的副本来构建。

    理论上,这应该可以在 Windows 上构建,但可以正常工作 事实证明,Windows 上的 GNU 构建环境很困难。

    我们在上面已经确认 Oracle JDK 7u3 支持PrintAssembly。我按照 hsdis 插件自述文件的说明,下载了 GNU binutils 2.22,将其放在 hsdis build/binutils 目录中并运行 make。这最终产生了以下错误:

    hsdis.c:32:20: error: sysdep.h: No such file or directory
    

    为了纠正这个问题,我使用以下补丁更改了 hsdis.c:

    diff -r 6259c6d3bbb7 src/share/tools/hsdis/hsdis.c
    --- a/src/share/tools/hsdis/hsdis.c Mon Dec 12 23:08:01 2011 -0800
    +++ b/src/share/tools/hsdis/hsdis.c Thu Feb 23 09:26:37 2012 -0500
    @@ -29,7 +29,7 @@
    
     #include "hsdis.h"
    
    -#include <sysdep.h>
    +#include <errno.h>
     #include <libiberty.h>
     #include <bfd.h>
     #include <dis-asm.h>
    

    然后运行make 成功。现在只需将hsdis build 目录下的hsdis-i386.so 插件复制到Oracle JDK 7u3 jre/lib/i386 目录即可。

    现在可以看到反汇编的编译代码了:

    $ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main
    CompilerOracle: print *Main.main
    Java HotSpot(TM) Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
    Compiled method (c2)      68    1 %           Main::main @ 4 (49 bytes)
     total in heap  [0xb3999548,0xb39999ec] = 1188
     relocation     [0xb3999610,0xb3999624] = 20
     main code      [0xb3999640,0xb3999840] = 512
     stub code      [0xb3999840,0xb3999850] = 16
     oops           [0xb3999850,0xb3999858] = 8
     scopes data    [0xb3999858,0xb3999898] = 64
     scopes pcs     [0xb3999898,0xb39999e8] = 336
     dependencies   [0xb39999e8,0xb39999ec] = 4
    Loaded disassembler from [snip]/jdk1.7.0_03/jre/lib/i386/hsdis-i386.so
    Decoding compiled method 0xb3999548:
    Code:
    [Disassembling for mach='i386']
    [Entry Point]
    [Verified Entry Point]
    [Constants]
      # {method} 'main' '([Ljava/lang/String;)V' in 'Main'
      0xb3999640: call   0xb6ff8510         ;   {runtime_call}
      0xb3999645: data32 xchg %ax,%ax
      0xb3999648: mov    %eax,-0x3000(%esp)
      0xb399964f: push   %ebp
      0xb3999650: sub    $0x38,%esp
      0xb3999656: mov    %ecx,%esi
      0xb3999658: mov    0x4(%esi),%ebp
      0xb399965b: mov    0x8(%esi),%edi
      0xb399965e: mov    (%ecx),%esi
      0xb3999660: mov    %ecx,(%esp)
      0xb3999663: call   0xb7078cf0         ;*iload_3
    [snip]
      0xb399983e: hlt    
      0xb399983f: hlt    
    [Exception Handler]
    [Stub Code]
      0xb3999840: jmp    0xb39981e0         ;   {no_reloc}
    [Deopt Handler Code]
      0xb3999845: push   $0xb3999845        ;   {section_word}
      0xb399984a: jmp    0xb397e220         ;   {runtime_call}
      0xb399984f: .byte 0x0
    OopMapSet contains 1 OopMaps
    
    #0 
    OopMap{off=468}
    

    我用过的测试类是:

    public class Main {
        public static void main(final String[] args) {
            long x = 0;
            for (int i = 0; i < 1000000; i++) {
                x += calculate(i);
            }
            System.out.println("x=" + x);
        }
    
        private static long calculate(final int i) {
            return (long)i * (long)i;
        }
    }
    

    【讨论】:

    • 非常感谢您的回复,我无法理解我在哪里找到了 hsdis 以及如何安装它?我不明白我应该在哪里创建这个构建目录。从现在开始,我已经在hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/… 下载了文件,并且我已经下载了 binutils-2.22。当您谈到binutils 时,它的整个目录只是名为 binutils 的子目录?
    • @alain.janinm 来自 hsdis 自述文件:The makefile looks for the sources in build/binutils or you can specify it's location to the makefile using BINTUILS=path. build/binutils 相对于 hsdis 文件所在的目录。在此目录中,您可以尝试类似 mkdir build ; cd build ; wget -O - http://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2 | tar xjvf - ; ln -s binutils-2.2.22 binutils 的内容。或者试试BINUTILS=path_to_where_you_extracted_binutils make
    • @DanCruz - 我认为最后一行应该是 ln -s binutils-2.22 binutils 而不是 ln -s binutils-2.2.22 binutils,但除此之外,太棒了。
    • @DanCruz 我试图编译它,但我得到一个编译器错误“bad reloc address 0x0”。你遇到过这样的问题吗?如果是这样,您可以在这里stackoverflow.com/questions/21042809/…回答我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    相关资源
    最近更新 更多