在Windows上运行-XX:CompileCommand

HotSpot JVM提供了几个与即时JIT )编译有关的命令行参数。 在本文中,我介绍了开始应用命令行标志-XX:CompileCommand所需的步骤,以查看对单个方法执行的即时编译。

JIT概述

Nikita Salnikov-Tarnovski的博客文章您是否能及时编译? 很好地概述了JIT编译器以及为什么需要它。 以下是该描述的摘录:


欢迎–热点。 该名称源自JVM识别应用程序中“热点”(经常执行的字节代码块)的功能。 然后将它们作为目标,以进行广泛的优化并将其编译为处理器专用指令。 …JVM中负责这些优化的组件称为即时编译器(JIT)。 …Java HotSpot VM不会及时编译所有代码,而是立即使用解释器运行程序,并在运行时分析代码以检测程序中的关键热点。 然后,它将全球本地代码优化器的注意力集中在热点上。

IBM文档JIT编译器概述还提供了JIT的简要概述,并指出以下内容:


实际上,方法不是在第一次调用时编译的。 对于每种方法,JVM维护一个调用计数,每次调用该方法时,该计数都会增加。 JVM解释一个方法,直到其调用计数超过JIT编译阈值为止。 因此,经常使用的方法在JVM启动后立即进行编译,而较少使用的方法则在以后编译,或者根本不编译。 JIT编译阈值可帮助JVM快速启动,并仍具有改进的性能。 精心选择了阈值,以在启动时间和长期性能之间获得最佳平衡。

识别JIT编译方法

因为JIT编译仅在调用和解释了-XX:CompileThreshold指定的次数( 针对服务器JVM 10,000以及针对客户端JVM 5,000 )指定的次数之后才针对特定方法“启动”,所以并非所有方法都将被编译JIT编译器。 HotSpot命令行选项-XX:+ PrintCompilation对于确定哪些方法已达到此阈值并已进行编译非常有用。 使用此选项显示的任何输出方法都是已编译方法,可以使用-XX:CompileCommand收集其编译详细信息。

以下屏幕快照演示了如何使用-XX:+PrintCompilation标识JIT编译的方法。 所显示的方法都不是简单应用程序本身的方法。 所有方法运行的时间足以满足从解释到实时编译的阈值,是“系统”方法。

在Windows上运行-XX:CompileCommand

使用-XX:CompileCommand在指定方法的编译后打印生成的汇编代码 ”的前提条件之一是使用-XX:+ UnlockDiagnosticVMOptions解锁用于诊断JVM的选项 ”。

针对查看JIT编译创建的“生成的汇编程序代码”的方法运行-XX:CompileCommand所需的另一个依赖项是包含反汇编程序插件 Project Kenai包含用于热点下载Basic Disassembler插件页面 ,可用于访问这些插件 ,但是Kenai Project正在关闭 在线资源“ 如何在Windows上构建hsdis-amd64.dll和hsdis-i386.dll”详细介绍了如何为Windows构建反汇编程序插件。 Lukas Stadler记录了对反汇编程序插件的需求,并提供了指向“ Windows x86预编译二进制文件” hsdis-i386.zip

我发现访问Windows兼容反汇编程序插件的最简单方法是从http://fcml-lib.com/download.html免费代码操纵库 (FCML)下载页面下载该插件。 撰写本文时,最新下载版本为fcml-1.1.1(04.08.2015) 可以为“用于64位Java VM的可从外部加载的反汇编程序插件”下载hsdis-1.1.1-win32-amd64.zip并提供其他下载选项,如下一个屏幕快照所示。

在Windows上运行-XX:CompileCommand

下一个屏幕快照演示了一个错误,如果未下载此反汇编程序插件并将其放置在正确的目录中,将会发生此错误。

在Windows上运行-XX:CompileCommand

错误消息指出:“ 无法加载hsdis-amd64.dll; 库不可加载; PrintAssembly已禁用 ”。 ZIP文件hsdis-1.1.1-win32-amd64.zip有一个hsdis-amd64.dll ,可以从FMCL下载 现在,我们只需要从ZIP文件中提取hsdis-amd64.dll文件,然后将其复制到相应的JRE目录中即可。

需要将反汇编程序插件JAR放置在与运行Java启动器( java )时应用的JRE相关的jre/bin/serverjre/bin/client目录中。 就我而言,我知道我的路径已定义为可以根据我的JAVA_HOME环境变量设置从JRE获取Java可执行文件(包括Java启动器)。 下一个屏幕快照显示了哪个目录,我将需要将反汇编程序插件JAR复制到JDK的“ jre”目录中,而不是复制到非JDK的“ jre”目录中。

在Windows上运行-XX:CompileCommand

知道我的Java启动器( java )已用完JDK的“ jre”安装后,我知道需要将反汇编程序插件JAR复制到该目录下的相应子目录中。 在我的情况下,有一个“服务器”子目录,没有“客户机”子目录,因此我想将反汇编程序插件JAR复制到%JAVA_HOME%\jre\bin\server

看到JIT编译方法生成的汇编代码

通过将反汇编程序插件JAR复制到我的JRE的bin/server子目录中,我现在可以包括命令行选项-XX:CompileCommand =print并带有特定的方法名称,以查看JIT编译时该方法生成的汇编代码。 就我而言,由于我自己的简单应用程序没有任何方法可以解释足够的时间来触发JIT,因此我将监视“系统”方法。 在这种情况下,我指定选项“ -XX:CompileCommand=print,java/lang/String.hashCode ”打印出String.hashCode()方法生成的汇编代码。 下一个屏幕快照对此进行了演示。

在Windows上运行-XX:CompileCommand

此屏幕快照包括几个确认,我们已经使用-XX:CompileCommand正确设置了必要的依赖-XX:CompileCommand 这些确认包括消息的存在,“从...加载反汇编程序”和“解码编译方法...”。 仅仅存在比以前更多的输出以及存在汇编程序代码,这些都是对成功使用-XX:CompilerCommand来打印方法生成的汇编程序代码的明显验证。

解密汇编代码

至此,真正的工作开始了。 现在可以分析已打印的生成的汇编代码,并且可以基于此分析来更改方法。 当然,这类工作需要汇编语法的知识。

我没有在本文中介绍选项-XX:+ PrintAssembly ,因为一次查看所有生成的汇编代码与查看特定选择的方法的汇编代码很少有用。 我喜欢马丁·汤普森(Martin Thompson) 阐明的问题,“ [使用-XX:+PrintAssembly ]会使您处于无法看到森林的状况。”

结论

HotSpot JVM选项-XX:CompileCommand对于影响和监视即时编译器的行为很有用。 这篇文章展示了如何使用“ print ”命令在Windows环境中应用该选项,以查看为该方法生成的汇编代码,该方法已经被解释了足够多次,可以被编译为汇编代码,以便日后访问。

翻译自: https://www.javacodegeeks.com/2016/09/running-xxcompilecommand-windows.html