简体   繁体   English

如何在 JVM 中查看 JIT 编译的代码?

[英]How to see JIT-compiled code in JVM?

有没有办法在 JVM 中查看 JIT 生成的本机代码?

General usage一般用途

As explained by other answers, you can run with the following JVM options:正如其他答案所述,您可以使用以下 JVM 选项运行:

-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

Filter on a specific method过滤特定方法

You can also filter on a specific method with the following syntax:您还可以使用以下语法过滤特定方法:

-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod

Notes:笔记:

  • you might need to put the second argument within quotes depending on OS etc.根据操作系统等,您可能需要将第二个参数放在引号内。
  • if the method gets inlined, you could miss some optimisations如果方法被内联,你可能会错过一些优化

How to: Install the required libraries on Windows如何:在 Windows 上安装所需的库

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.dllhsdis-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.dllhsdis-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

  1. 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类别中)
  2. 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>\\ ) .

  3. Download the latest GNU binutils source package and extract its contents to your Cygwin home directory.下载最新的 GNU binutils 源包并将其内容解压缩到您的 Cygwin 主目录。 At the time of writing, the latest package is 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.这应该会在您的 Cygwin 主目录中生成一个名为binutils-2.25 (或任何最新版本)的目录。
  4. Download the OpenJDK source by going to the JDK 8 Updates repository , selecting the tag corresponding to your installed JRE version, and clicking bz2.通过转至 JDK 8 更新存储库,选择与您安装的 JRE 版本对应的标签,然后单击 bz2下载 OpenJDK 源代码。 Extract the hsdis directory (found in src\\share\\tools ) to your Cygwin home directory.将 hsdis 目录(在src\\share\\tools找到)解压到您的 Cygwin 主目录。
  5. In the Cygwin Terminal, enter cd ~/hsdis .在 Cygwin 终端中,输入cd ~/hsdis
  6. 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 无法识别它。

  7. The build will fail with messages ./chew: No such file or directory and gcc: command not found .构建将失败并显示消息./chew: No such file or directorygcc: 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 .在 Wordpad 或 Notepad++ 等文本编辑器中编辑<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-amd64hsdis\\build\\Linux-i586复制到 JRE 的bin\\serverbin\\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下载部分中提供的预构建库:

To install in Windows:在 Windows 中安装:

  • Extract the dll (it can be found in hsdis-1.1.2-win32-i386.zip and hsdis-1.1.2-win32-amd64.zip).提取 dll(可以在 hsdis-1.1.2-win32-i386.zip 和 hsdis-1.1.2-win32-amd64.zip 中找到)。
  • Copy the dll to wherever exists java.dll (use Windows search).将 dll 复制到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

To install in Linux:在 Linux 中安装:

  • Download source code, extract it下载源代码,解压
  • 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
  • On my system, the JDK is in /usr/lib/jvm/java-8-oracle在我的系统上,JDK 位于/usr/lib/jvm/java-8-oracle

How to run it:如何运行它:

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.我刚刚运行了一个罐子。

  • Then I attached to the java process through Windbg然后我通过Windbg附加到java进程
  • Examined threads by ~ command;通过~命令检查线程; There were 11 threads, 0 thread was main worker thread有 11 个线程,0 个线程是主工作线程
  • Switched to 0-thread - ~0s切换到 0 线程 - ~0s
  • 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 there00402f68放在那里
    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 分析器( LinuxPerfAsmProfilerWinPerfAsmProfiler )打印热点的组装。 JMH does require the hsdis library since it relies on PrintAssembly . JMH 确实需要hsdis库,因为它依赖PrintAssembly

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM