有没有一种方法可以查看JVM中JIT生成的本机代码?
有没有一种方法可以查看JVM中JIT生成的本机代码?
正如其他答案所解释的那样,您可以使用以下JVM选项运行:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
你也可以使用以下语法来筛选特定方法:
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
注:
如果您正在运行Windows,则此页面提供了有关如何构建和安装hsdis-amd64.dll
和hsdis-i386.dll
所需的说明。以下为参考内容:
获取预构建的二进制文件
您可以从fcml项目下载Windows的预构建二进制文件
如何在Windows上构建hsdis-amd64.dll
和hsdis-i386.dll
本指南版本是在Windows 8.1 64位上使用64位Cygwin准备的,并生成hsdis-amd64.dll。
安装Cygwin。在选择软件包
屏幕上,添加以下软件包(通过展开Devel
类别,然后单击每个包名称旁边的Skip
标签来实现):
make
mingw64-x86_64-gcc-core
(仅对hsdis-amd64.dll
需要)mingw64-i686-gcc-core
(仅对hsdis-i386.dll
需要)diffutils
(在Utils
类别中)运行Cygwin终端。可以使用安装程序创建的桌面或开始菜单图标完成,将创建您的Cygwin主目录(默认情况下为C:\ cygwin \ home \<username>\
或C:\ cygwin64 \ home \<username>\
)。
binutils-2.25.tar.bz2
。这应该会在您的Cygwin主目录中创建一个名为binutils-2.25
(或任何最新版本)的目录。cd ~/hsdis
。要构建hsdis-amd64.dll
,请输入
make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar'
/usr/lib/
中。 - Jean-François Savardhsdis
。它行不通。 - Aleksandr DubinskyPrintAssembly
。一个方便的选择是基于FCML库的hsdis插件。java.dll
的任何位置(使用Windows搜索)。 在我的系统上,我在两个位置找到了它:
C:\Program Files\Java\jre1.8.0_45\bin\server
C:\Program Files\Java\jdk1.8.0_45\jre\bin\server
cd <源代码目录>
./configure && make && sudo make install
cd example/hsdis && make && sudo make install
sudo ln -s /usr/local/lib/libhsdis.so <JDK路径>/lib/amd64/hsdis-amd64.so
sudo ln -s /usr/local/lib/libhsdis.so <JDK路径>/jre/lib/amd64/hsdis-amd64.so
/usr/lib/jvm/java-8-oracle
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
-XX:+LogCompilation -XX:PrintAssemblyOptions=intel,mpad=10,cpad=10,code
-jar fcml-test.jar
额外的配置参数:
code 在助记符之前打印机器代码。
intel 使用Intel语法。
gas 使用AT&T汇编器语法(GNU汇编器兼容)。
dec 以十进制值打印IMM和位移。
mpad=XX 指令助记符部分的填充。
cpad=XX 机器代码的填充。
seg 显示默认段寄存器。
zeros 在HEX字面量的情况下显示前导零。
在Windows上,Intel语法是默认语法,而在GNU/Linux上,AT&T语法是默认语法。
有关更多详细信息,请参见FCML库参考手册。
apt-get install libhsdis0-fcml
(https://askubuntu.com/a/991166/489909)。自己构建可能并不必要。 - David Georg Reichelt对于HotSpot(曾经是Sun)JVM,即使在产品模式下:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
需要一些汇编语言的知识:它需要一个插件。
如果您在Windows机器上运行它,我相信WinDbg会非常有帮助。
我刚刚运行了一个jar文件。
通过kb查看未管理的调用堆栈,其中包括:
0008fba8 7c90e9c0 ntdll!KiFastSystemCallRet
0008fbac 7c8025cb ntdll!ZwWaitForSingleObject+0xc
0008fc10 7c802532 kernel32!WaitForSingleObjectEx+0xa8
0008fc24 00403a13 kernel32!WaitForSingleObject+0x12
0008fc40 00402f68 java+0x3a13
0008fee4 004087b8 java+0x2f68
0008ffc0 7c816fd7 java+0x87b8
0008fff0 00000000 kernel32!BaseProcessStart+0x23
加粗的行是在JVM上直接执行JIT代码的结果。
接下来我们可以查找方法地址:
java+0x2f68是00402f68
在WinDBG上:
点击查看 ->
反汇编。
点击编辑 --> 转到
地址。
放入00402f68,然后获得
00402f68 55 push ebp
00402f69 8bec mov ebp,esp
00402f6b 81ec80020000 sub esp,280h
00402f71 53 push ebx
00402f72 56 push esi
00402f73 57 push edi
... 以此类推
如果需要其他信息,请参阅示例,了解如何使用进程资源管理器和WinDbg从内存转储中追溯JIT代码。
另一种查看机器代码和性能数据的方法是使用AMD的CodeAnalyst或OProfile,它们具有用于将执行的Java代码可视化为机器代码的Java插件。
LinuxPerfAsmProfiler
或WinPerfAsmProfiler
)打印您的热点代码的汇编信息。由于其依赖于PrintAssembly
,因此JMH需要hsdis
库。保留HTML标签。