JDK的命令行工具——JIT生成代码反汇编(HSDIS)。

        HSDIS是一个Sun官方推荐的HotSpot虚拟机JIT编译代码的反汇编插件,他包含在HotSpot虚拟机的源码之中,但没有提供编译后的程序。在Project Kenai的网站也可以下载到单独的源码。他的作用是让HotSpot的-XX : +PrintAssembly指令调用他来把动态生成的本地代码还原为汇编代码输出,同时还生成了大量非常有价值的注释,这样我们就可以通过输出的代码来分析问题。可以根据自己的操作系统和CPU类型从Project Kenai的网站上下载编译好的插件,直接放到JDK_HOME/jre/bin/client和JDK_HOME/jre/bin/server目录中即可。如果没有找到所需操作系统(譬如Windows的就没有)的成品,那就得自己使用源码编译一下。

        还需要注意的是,如果使用的是Debug或者FastDebug版的HotSpot,那可以直接通过-XX : +PringAssembly指令使用插件;如果使用的是Product版的HotSpot,那还要额外加入一个-XX : +UnlockDiagnostic VMOption参数。以下面简单测试代码为例演示一下这个插件的使用。

public class Bar {
    int a = 1;
    static int b = 2;

    public int sum(int c) {
        return a + b + c;
    }

    public static void main(String[] args) {
        new Bar().sum(3);
    }
}

         编译这段代码,并使用以下命令执行。

        其中,参数-Xcomp是让虚拟机以编译模式执行代码,这样代码可以“偷懒”,不需要执行足够次数来预热就能触发JIT编译。两个-XX : CompileCommand意思是让编译器不要内联sum()并且只编译sum(),-XX : +PrintAssembly就是输出反汇编内容。如果一切顺序的话,那么屏幕上会出现类似下面内容。

JDK的命令行工具——JIT生成代码反汇编(HSDIS)。_第1张图片

         上段代码并不多,下面一句句进行说明。

  1. mov%eax, -0x8000(%esp) : 检查栈溢。
  2. push%ebp : 保存上一栈帧基址。
  3. sub$0x18 , %esp :给新帧分配空间。
  4. mov 0x8 (%ecx) , %eax : 取实例变量a,这里0x8(%ecx)就是ecx+0x8的意思,前面“[Constants]”节中提示了“this : ecx='test/Bar'”,即ecx寄存器中放的就是this对象的地址。偏移0x8是越过this对象的对象头,之后就是实例变量a的内存位置。这次是访问“Java堆”中的数据。
  5. move$0x3d2fad8,%esi :取test.Bar在方法区的指针。
  6. mov 0x68 (%esi) , %esi :取类变量b,这次是访问“方法区”中的数据。
  7. add%esi , %eax和add%edx, %eax:做两次加法,求a+b+c的值,前面的代码把a放在eax中,把b放在esi中,而c在[Constants]中提示了,“parm() : edx=int”,说明c在edx中。
  8. add$0x18, %esp : 撤销栈帧。
  9. pop%edp:恢复上一栈帧。
  10. test%eax , 0X2b0100:轮询方法返回处的SafePoint。
  11. ret:方法返回。

你可能感兴趣的:(运维)