一、背景
我们知道,通过javap命令可以查看字节码信息,我们通过字节码可以知道对于一个程序,虚拟机做了些什么事情。但是各大虚拟机厂商对其的实现细节可能会大不相同,字节码只能从语义上解释程序的执行。如果我们要分析程序在宿主环境中到底是如何运行的,字节码则不能给我们提供足够详细的信息了,这个时候我们就需要站在汇编的角度考虑问题。
二、HSDIS
HSDIS是sun推荐的HotSpot虚拟机JIT编译代码的反汇编插件,它包含在HotSpot虚拟机的源码中,但没有提供编译后的程序。HotSpot的-XX:PrintAssemBly指令可以调用它来把本地代码还原为汇编代码输出,同时还生成了一些注释。由于编译比较麻烦,这里就直接贴出可用于windows64位的下载地址:
链接: https://pan.baidu.com/s/1POT2B96z2FFu3qpfbb7pBw
提取码: 2xe9
下载该文件后放到JDK_HOME/jre/bin/server或JDK_HOME/jre/bin/client下即可。
三、实践
首先我们定义一个类(代码本身没有什么实际的意义):
public class Test {
public static void print(int n) {
for (int i = 0; i < n; i++) {
System.out.println(i);
}
}
public static void main(String[] args) {
Test.print(10);
}
}
我们首先需要使用javac编译源码文件:
javac Test.java
然后使用HSDIS插件进行反汇编:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:LogFile=b.log -Xcomp -XX:CompileCommand=compileonly,Test.print Test
其中的参数含义如下:
-XX:+UnlockDiagnosticVMOptions:Product版的HotSpot则需要加上此参数,如果是Debug或FastDebug版的HotSpot,则可以忽略它
-XX:+PrintAssembly:表示输出反汇编内容
-XX:+LogCompilation:表示生成日志文件
-XX:LogFile:日志文件路径(生成日志文件之后,可以用其它工具做详细分析,比如JITWatch)
-Xcomp:让虚拟机以编译模式执行代码,使用它我们可以不必做预热操作就能触发JIT编译(如果该参数在实际使用的虚拟机中已经被移除,那么还是需要做预热才能触发JIT编译,简单做个循环预热就可以了)
-XX:CompileCommand:用于指定compile指令。我们配置compileonly,表示只编译Test#print方法