有什么方法可以查看JIT在JVM中生成的本机代码吗?
有什么方法可以查看JIT在JVM中生成的本机代码吗?
Answers:
如其他答案所述,您可以使用以下JVM选项运行:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
您还可以使用以下语法筛选特定方法:
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
笔记:
如果您运行的是Windows,则此页面包含有关如何构建和安装hsdis-amd64.dll
以及hsdis-i386.dll
使其工作所需的说明。我们在下面复制并扩展该页面的内容*,以供参考:
从哪里获取预构建的二进制文件
您可以从fcml项目下载Windows的预编译二进制文件
如何建立hsdis-amd64.dll
和hsdis-i386.dll
在Windows
该版本的指南是在Windows 8.1 64位上使用64位Cygwin编写的,并生成hsdis-amd64.dll
安装Cygwin。在Select Packages
屏幕上,添加以下软件包(通过展开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
。这将binutils-2.25
在您的Cygwin主目录中生成一个名为(或最新版本)的目录。src\share\tools
)提取到Cygwin主目录中。cd ~/hsdis
。要构建hsdis-amd64.dll
,请输入
make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
要构建hsdis-i386.dll
,请输入
make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
无论哪种情况,都请替换2.25
为您下载的binutils版本。OS=Linux
这是必要的,因为尽管Cygwin是一个类似Linux的环境,但是hsdis makefile无法如此识别它。
./chew: No such file or directory
和gcc: command not found
。<Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefile
在诸如Wordpad或Notepad ++之类的文本编辑器中进行编辑,以将其更改为SUBDIRS = doc po
(如果使用binutils 2.25,则为第342行)SUBDIRS = po
。重新运行上一个命令。该DLL现在可以通过从复制它被安装hsdis\build\Linux-amd64
或hsdis\build\Linux-i586
您的JREbin\server
或bin\client
目录。您可以通过搜索在系统上找到所有此类目录java.dll
。
温馨提示:如果您更喜欢Intel ASM语法而不是AT&T,请-XX:PrintAssemblyOptions=intel
在使用的任何其他PrintAssembly选项中指定。
*页面许可为知识共享
/usr/lib/
您需要一个hsdis插件才能使用PrintAssembly
。一个方便的选择是基于FCML库的hsdis插件。
可以针对类似UNIX的系统对其进行编译,并且在Windows上,可以使用Sourceforge的FCML下载部分中提供的预构建库:
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 <source code dir>
./configure && make && sudo make install
cd example/hsdis && make && sudo make install
sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/lib/amd64/hsdis-amd64.so
sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/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在十六进制文字的情况下显示前导零。
对于Windows,Intel语法是默认语法,而对于GNU / Linux,AT&T是默认语法。
有关更多详细信息,请参见《FCML库参考手册》
apt-get install libhsdis0-fcml
(askubuntu.com/a/991166/489909)。您自己构建此文件可能不是必需的。
对于HotSpot(是Sun)JVM,即使在产品模式下:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
需要一些组装:它需要一个插件。
我相信WinDbg如果在Windows计算机上运行它会有所帮助。我刚一罐。
通过kb浏览无误的调用栈,发现:
0008fba8 7c90e9c0 NTDLL!KiFastSystemCallRet
0008fbac 7c8025cb NTDLL!ZwWaitForSingleObject + 0xC的
0008fc10 7c802532 KERNEL32!WaitForSingleObjectEx + 0xa8
0008fc24 00403a13 KERNEL32!WaitForSingleObject的+ 0×12
0008fc40 00402f68的java + 0x3a13
0008fee4 004087b8的java + 0x2f68
0008ffc0 7c816fd7的java + 0x87b8
0008fff0 00000000 KERNEL32!BaseProcessStart + 0×23
突出显示的行是在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版本的代码。
使用JMH的perfasm分析器(LinuxPerfAsmProfiler
或WinPerfAsmProfiler
)打印热点的装配体。JMH确实需要该hsdis
库,因为它依赖PrintAssembly
。