[英]How to see JIT-compiled code in JVM?
有没有办法在 JVM 中查看 JIT 生成的本机代码?
As explained by other answers, you can run with the following JVM options:正如其他答案所述,您可以使用以下 JVM 选项运行:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
You can also filter on a specific method with the following syntax:您还可以使用以下语法过滤特定方法:
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod
Notes:笔记:
If you are running Windows, this page has instructions on how to build and install hsdis-amd64.dll
and hsdis-i386.dll
which are required to make it work.如果您运行的是 Windows,此页面包含有关如何构建和安装
hsdis-amd64.dll
和hsdis-i386.dll
,这些是使其工作所需的。 We copy below and extend the content of that page* for reference:我们在下面复制并扩展该页面*的内容以供参考:
Where to get prebuilt binaries从哪里获得预构建的二进制文件
You can download prebuilt binaries for Windows from the fcml project您可以从fcml项目下载适用于 Windows 的预构建二进制文件
How to build hsdis-amd64.dll
and hsdis-i386.dll
on Windows如何在 Windows 上构建
hsdis-amd64.dll
和hsdis-i386.dll
This version of the guide was prepared on Windows 8.1 64bit using 64-bit Cygwin and producing hsdis-amd64.dll此版本的指南是在 Windows 8.1 64bit 上使用 64 位 Cygwin 编写的,并生成 hsdis-amd64.dll
Install Cygwin .安装 Cygwin 。 At the
Select Packages
screen, add the following packages (by expanding the Devel
category, then clicking once on the Skip
label next to each package name):在
Select Packages
屏幕上,添加以下包(通过展开Devel
类别,然后单击每个包名称旁边的Skip
标签):
make
mingw64-x86_64-gcc-core
(only needed for hsdis-amd64.dll
) mingw64-x86_64-gcc-core
(仅hsdis-amd64.dll
需要)mingw64-i686-gcc-core
(only needed for hsdis-i386.dll
) mingw64-i686-gcc-core
(仅hsdis-i386.dll
需要)diffutils
(in Utils
category) diffutils
(在Utils
类别中) Run the Cygwin Terminal.运行 Cygwin 终端。 This can be done using the Desktop or Start Menu icon created by the installer, and will create your Cygwin home directory (
C:\\cygwin\\home\\<username>\\
or C:\\cygwin64\\home\\<username>\\
by default).这可以使用安装程序创建的桌面或开始菜单图标来完成,并将创建您的 Cygwin 主目录(默认为
C:\\cygwin\\home\\<username>\\
或C:\\cygwin64\\home\\<username>\\
) .
binutils-2.25.tar.bz2
.binutils-2.25.tar.bz2
。 This should result in a directory named binutils-2.25
(or whatever the latest version is) in your Cygwin home directory.binutils-2.25
(或任何最新版本)的目录。src\\share\\tools
) to your Cygwin home directory.src\\share\\tools
找到)解压到您的 Cygwin 主目录。cd ~/hsdis
.cd ~/hsdis
。 To build hsdis-amd64.dll
, enter要构建
hsdis-amd64.dll
,请输入
make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
To build hsdis-i386.dll
, enter要构建
hsdis-i386.dll
,请输入
make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
In either case, replace 2.25
with the binutils version you downloaded.无论哪种情况,都将
2.25
替换为您下载的 binutils 版本。 OS=Linux
is necessary because, although Cygwin is a Linux-like environment, the hsdis makefile fails to recognize it as such. OS=Linux
是必要的,因为尽管 Cygwin 是一个类似 Linux 的环境,但 hsdis makefile 无法识别它。
./chew: No such file or directory
and gcc: command not found
../chew: No such file or directory
和gcc: command not found
。 Edit <Cygwin home directory>\\hsdis\\build\\Linux-amd64\\bfd\\Makefile
in a text editor like Wordpad or Notepad++ to change SUBDIRS = doc po
(line 342, if using binutils 2.25) to SUBDIRS = po
.<Cygwin home directory>\\hsdis\\build\\Linux-amd64\\bfd\\Makefile
,将SUBDIRS = doc po
(第 342 行,如果使用 binutils 2.25)更改为SUBDIRS = po
。 Re-run the previous command. The DLL can now be installed by copying it from hsdis\\build\\Linux-amd64
or hsdis\\build\\Linux-i586
to your JRE's bin\\server
or bin\\client
directory.现在可以通过将 DLL 从
hsdis\\build\\Linux-amd64
或hsdis\\build\\Linux-i586
复制到 JRE 的bin\\server
或bin\\client
目录来安装 DLL。 You can find all such directories on your system by searching for java.dll
.您可以通过搜索
java.dll
在系统上找到所有此类目录。
Bonus tip: if you prefer Intel ASM syntax to AT&T, specify -XX:PrintAssemblyOptions=intel
alongside any other PrintAssembly options you use.额外提示:如果您更喜欢英特尔 ASM 语法而不是 AT&T,请在您使用的任何其他 PrintAssembly 选项旁边指定
-XX:PrintAssemblyOptions=intel
。
*page license is Creative Commons *页面许可是知识共享
Assuming you're using the Sun Hotspot JVM (ie the one provided on java.com by Oracle), you can add the flag假设您使用的是 Sun Hotspot JVM(即 Oracle 在java.com 上提供的那个),您可以添加标志
-XX:+PrintOptoAssembly
-XX:+PrintOptoAssembly
when running your code.运行代码时。 This will print out the optimized code generated by the JIT compiler and leaves out the rest.
这将打印出由 JIT 编译器生成的优化代码并忽略其余部分。
If you want see the entire bytecode, including the unoptimized parts, add如果您想查看整个字节码,包括未优化的部分,请添加
-XX:CompileThreshold=#
-XX:CompileThreshold=#
when you're running your code.当你运行你的代码时。
You can read more about this command and the functionality of JIT in general here .您可以在此处阅读有关此命令和 JIT 功能的更多信息。
You need an hsdis plugin to use PrintAssembly
.您需要一个 hsdis 插件才能使用
PrintAssembly
。 A convenient choice is the hsdis plugin based on FCML library.一个方便的选择是基于 FCML 库的 hsdis 插件。
It can be compiled for UNIX-like systems and on Windows you can use pre-built libraries available in the FCML download section on Sourceforge:它可以为类 UNIX 系统编译,在 Windows 上,您可以使用 Sourceforge 上的 FCML下载部分中提供的预构建库:
java.dll
(use Windows search).java.dll
存在的任何位置(使用 Windows 搜索)。 On my system, I found it at two locations: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
/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
Additional configuration parameters:附加配置参数:
code Print machine code before the mnemonic.
code在助记符之前打印机器代码。
intel Use the Intel syntax.
intel使用 Intel 语法。
gas Use the AT&T assembler syntax (GNU assembler compatible).
gas使用 AT&T 汇编器语法(GNU 汇编器兼容)。
dec Prints IMM and displacement as decimal values.
dec 将IMM 和位移打印为十进制值。
mpad=XX Padding for the mnemonic part of the instruction.
mpad=XX填充指令的助记符部分。
cpad=XX Padding for the machine code.
cpad=XX 机器码的填充。
seg Shows the default segment registers.
seg显示默认段寄存器。
zeros Show leading zeros in case of HEX literals.
zeros在十六进制文字的情况下显示前导零。
The Intel syntax is a default one in case of Windows, whereas the AT&T one is a default for the GNU/Linux. Intel 语法是 Windows 的默认语法,而 AT&T 语法是 GNU/Linux 的默认语法。
For more details see the FCML Library Reference Manual有关更多详细信息,请参阅FCML 库参考手册
For the HotSpot (was Sun) JVM, even in product modes:对于 HotSpot(以前是 Sun)JVM,即使在产品模式中:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
Some assembly required: it needs a plugin.需要一些程序集:它需要一个插件。
I believe WinDbg would be helpful if you are running it on windows machine.如果您在 Windows 机器上运行它,我相信 WinDbg 会有所帮助。 I have just run one jar.
我刚刚运行了一个罐子。
Looked through unmanmaged callstack by kb there was:通过kb查看非托管调用堆栈有:
0008fba8 7c90e9c0 ntdll!KiFastSystemCallRet 0008fba8 7c90e9c0 ntdll!KiFastSystemCallRet
0008fbac 7c8025cb ntdll!ZwWaitForSingleObject+0xc 0008fbac 7c8025cb ntdll!ZwWaitForSingleObject+0xc
0008fc10 7c802532 kernel32!WaitForSingleObjectEx+0xa8 0008fc10 7c802532 kernel32!WaitForSingleObjectEx+0xa8
0008fc24 00403a13 kernel32!WaitForSingleObject+0x12 0008fc24 00403a13 kernel32!WaitForSingleObject+0x12
0008fc40 00402f68 java+0x3a13 0008fc40 00402f68 java+0x3a13
0008fee4 004087b8 java+0x2f68 0008fee4 004087b8 java+0x2f68
0008ffc0 7c816fd7 java+0x87b8 0008ffc0 7c816fd7 java+0x87b8
0008fff0 00000000 kernel32!BaseProcessStart+0x23 0008fff0 00000000 kernel32!BaseProcessStart+0x23
Highlighted lines is direct running JIT-ed code on JVM.突出显示的行是在 JVM 上直接运行 JIT 代码。
Then we can look for method address:然后我们可以查找方法地址:
java+0x2f68 is 00402f68 java+0x2f68 是 00402f68
On WinDBG:在 WinDBG 上:
Click View --> Disassembly.单击查看 --> 反汇编。
Click Edit --> Go to Address.单击编辑 --> 转到地址。
Put 00402f68 there把00402f68放在那里
and got并得到
00402f68 55 push ebp 00402f68 55 推 ebp
00402f69 8bec mov ebp,esp 00402f69 8bec mov ebp,esp
00402f6b 81ec80020000 sub esp,280h 00402f6b 81ec80020000 sub esp,280h
00402f71 53 push ebx 00402f71 53 推 ebx
00402f72 56 push esi 00402f72 56 推 esi
00402f73 57 push edi 00402f73 57 推编辑
... and so on ……等等
For additional info here is the Example how to trace back JIT-ed code from memory dumps using process explorer and WinDbg.此处的其他信息是如何使用进程资源管理器和 WinDbg 从内存转储中追溯 JIT 代码的示例。
查看机器代码和一些性能数据的另一种方法是使用 AMD 的 CodeAnalyst 或 OProfile,它们有一个 Java 插件,可以将执行的 Java 代码可视化为机器代码。
Print the assembly of your hotspots with JMH's perfasm profilers ( LinuxPerfAsmProfiler
or WinPerfAsmProfiler
).使用 JMH 的 perfasm 分析器(
LinuxPerfAsmProfiler
或WinPerfAsmProfiler
)打印热点的组装。 JMH does require the hsdis
library since it relies on PrintAssembly
. JMH 确实需要
hsdis
库,因为它依赖PrintAssembly
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.