有什么方法可以查看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每个软件包名称旁边的标签上单击一次):
makemingw64-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\serverC:\Program Files\Java\jdk1.8.0_45\jre\bin\servercd <source code dir>./configure && make && sudo make installcd example/hsdis && make && sudo make installsudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/lib/amd64/hsdis-amd64.sosudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/jre/lib/amd64/hsdis-amd64.so/usr/lib/jvm/java-8-oraclejava -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。