如何在 JVM HotSpot 中使用 -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print 选项
我正在尝试使用 -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod 命令行questions/9336704/jvm-option-to-optimize-loop-statements#answer-9337542">这篇文章.
它似乎可以通过 open-jdk
(https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly).
如何在 oracle JDK7 和 JVM HotSpot 中使用这些选项(或类似选项)?
解决方案这些说明适用于 Linux (Ubuntu 10.04.4 LTS),但应该适用于您的操作系统.下载 Oracle JDK 7u3 并适当地设置你的 JAVA_HOME
和 PATH
环境变量,执行以下检查可用的选项:
java -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version
您应该看到 UnlockDiagnosticVMOptions
、CompileCommand
和 PrintAssembly
选项可用.使用 CompileCommand
选项也将启用 PrintAssembly
选项.但是,您需要 HotSpot 反汇编器插件才能使 PrintAssembly
工作;如果没有它,您可能会看到如下内容:
$ java -versionjava版本1.7.0_03"Java(TM) SE 运行时环境 (build 1.7.0_03-b04)Java HotSpot(TM) 服务器虚拟机(build 22.1-b02,混合模式)$ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main编译器Oracle:打印 *Main.mainJava HotSpot(TM) 服务器虚拟机警告:汇编代码打印已启用;打开 DebugNonSafepoints 以获得额外的输出编译方法 (c2) 68 1 % Main::main @ 4 (49 字节)堆中的总数 [0xb3a97548,0xb3a979ec] = 1188重定位 [0xb3a97610,0xb3a97624] = 20主代码 [0xb3a97640,0xb3a97840] = 512存根代码 [0xb3a97840,0xb3a97850] = 16哎呀 [0xb3a97850,0xb3a97858] = 8范围数据 [0xb3a97858,0xb3a97898] = 64范围 pcs [0xb3a97898,0xb3a979e8] = 336依赖项 [0xb3a979e8,0xb3a979ec] = 4无法加载 hsdis-i386.so;库不可加载;PrintAssembly 已禁用OopMapSet 包含 1 个 OopMaps
要获得 HotSpot 反汇编插件,您需要构建它.查看 OpenJDK 7u2 源代码,hsdis 插件自述文件 说:
<块引用>要将插件与 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: 错误: sysdep.h: 没有这样的文件或目录
为了纠正这个问题,我使用以下补丁更改了 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 2012 年 2 月 23 日星期四 09:26:37 -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
目录下即可.p>
现在可以看到反汇编的编译代码了:
$ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main编译器Oracle:打印 *Main.mainJava HotSpot(TM) 服务器虚拟机警告:汇编代码打印已启用;打开 DebugNonSafepoints 以获得额外的输出编译方法 (c2) 68 1 % Main::main @ 4 (49 字节)堆中的总数 [0xb3999548,0xb39999ec] = 1188重定位 [0xb3999610,0xb3999624] = 20主代码 [0xb3999640,0xb3999840] = 512存根代码 [0xb3999840,0xb3999850] = 16哎呀 [0xb3999850,0xb3999858] = 8范围数据 [0xb3999858,0xb3999898] = 64范围 pcs [0xb3999898,0xb39999e8] = 336依赖项 [0xb39999e8,0xb39999ec] = 4从 [snip]/jdk1.7.0_03/jre/lib/i386/hsdis-i386.so 加载反汇编程序解码编译方法0xb3999548:代码:[反汇编为 mach='i386'][入口点][验证入口点][常数]# {method} 'main' '([Ljava/lang/String;)V' in 'Main'0xb3999640:调用 0xb6ff8510 ;{runtime_call}0xb3999645: 数据 32 xchg %ax,%ax0xb3999648: 移动 %eax,-0x3000(%esp)0xb399964f:推送 %ebp0xb3999650: 低于 $0x38,%esp0xb3999656: 移动 %ecx,%esi0xb3999658: 移动 0x4(%esi),%ebp0xb399965b: 移动 0x8(%esi),%edi0xb399965e: 移动 (%ecx),%esi0xb3999660: 移动 %ecx,(%esp)0xb3999663: 调用 0xb7078cf0 ;*iload_3[剪辑]0xb399983e: hlt0xb399983f: hlt[异常处理程序][存根代码]0xb3999840:jmp 0xb39981e0;{no_reloc}[Deopt 处理程序代码]0xb3999845:推送$0xb3999845;{section_word}0xb399984a:jmp 0xb397e220;{runtime_call}0xb399984f:.byte 0x0OopMapSet 包含 1 个 OopMaps#0OopMap{off=468}
我用过的测试类是:
公共类 Main {公共静态无效主要(最终字符串[]参数){长 x = 0;for (int i = 0; i <1000000; i++) {x += 计算(i);}System.out.println("x=" + x);}私人静态长计算(最终int i){返回 (long)i * (long)i;}}
I 'm trying to use -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
command lines as described in this post.
It seems thats it's available with open-jdk
(https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly).
How can I use those options (or similar equivalents) with oracle JDK7 and the JVM HotSpot?
解决方案These instructions apply to Linux (Ubuntu 10.04.4 LTS), but should be applicable for your OS. After downloading Oracle JDK 7u3 and appropriately setting your JAVA_HOME
and PATH
environment variables, execute the following to check available options:
java -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version
You should see the UnlockDiagnosticVMOptions
, CompileCommand
and PrintAssembly
options are available. Using the CompileCommand
option will also enable the PrintAssembly
option. However, you will need the HotSpot disassembler plugin for PrintAssembly
to work; without it, you might see something like the following:
$ 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
To get the HotSpot disassembler plugin, you will need to build it. Looking at the OpenJDK 7u2 source, the hsdis plugin readme says:
To use the plugin with a JVM, you need a new version that can load it. If the product mode of your JVM does not accept -XX:+PrintAssembly, you do not have a version that is new enough.
To build this project you [need] a copy of GNU binutils to build against.
In theory this should be buildable on Windows but getting a working GNU build environment on Windows has proven difficult.
We have confirmed above that Oracle JDK 7u3 supports PrintAssembly
. I followed the hsdis plugin readme instructions, downloaded GNU binutils 2.22, placed it in the hsdis build/binutils
directory and ran make
. This eventually produced the following error:
hsdis.c:32:20: error: sysdep.h: No such file or directory
To correct this, I changed hsdis.c using the following patch:
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>
Running make
was then successful. Now just copy the hsdis-i386.so
plugin in the hsdis build
directory to the Oracle JDK 7u3 jre/lib/i386
directory.
Now you can see the disassembled compiled code:
$ 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}
The test class I've used is:
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;
}
}
相关文章