上一篇文章中提到了汇编指令unsafe中getAndAddInt性能疑问 ,正是由于对汇编不甚了解,导致走了很多误区。
这篇文章主要说下如何使用hsdis?
首先给出hsdis的下载地址官方地址,但是官方没有提供Windows的,iteye地址
这篇文章hsdis的使用方式,在OSX、Ubuntu14.04、Centos5.6测试通过,JDK7、JDK8都可。
假设本地hsdis存放目录$HOME/hsdis
下载的hsdis文件,需要根据系统修改为对应的名称,不知道如何修改的,可以根据错误提示修改。
设置环境变量
export LDLIBRARYPATH=$HOME/hsdis
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); } }
javac Bar.java
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp -XX:CompileCommand=dontinline,Bar.sum -XX:CompileCommand=compileonly,Bar.sum Bar
参数UnlockDiagnosticVMOptions从JDK7的某个版本开始必须加上。
参数PrintAssembly是输出反汇编内容
参数-Xcomp是让虚拟机以编译模式执行代码
参数dontinline是不对Bar.sum方法做内联优化
参数compileonly是仅仅编译Bar.sum方法
下面是汇编代码,这里顺便贴一下
Java HotSpot(TM) 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output CompilerOracle: dontinline Bar.sum CompilerOracle: compileonly Bar.sum Loaded disassembler from hsdis-amd64.dylib Decoding compiled method 0x000000010649b0d0: Code: [Disassembling for mach='i386:x86-64'] [Entry Point] [Constants] # {method} 'sum' '(I)I' in 'Bar' # this: rsi:rsi = 'Bar' # parm0: rdx = int # [sp+0x20] (sp of caller) 0x000000010649b200: mov 0x8(%rsi),%r10d 0x000000010649b204: shl $0x3,%r10 0x000000010649b208: cmp %r10,%rax 0x000000010649b20b: jne 0x0000000106470960 ; {runtime_call} 0x000000010649b211: data32 xchg %ax,%ax 0x000000010649b214: nopl 0x0(%rax,%rax,1) 0x000000010649b21c: data32 data32 xchg %ax,%ax [Verified Entry Point] 0x000000010649b220: sub $0x18,%rsp 0x000000010649b227: mov %rbp,0x10(%rsp) ;*synchronization entry ; - Bar::sum@-1 (line 5) 0x000000010649b22c: movabs $0x7aaadbf68,%r10 ; {oop(a 'java/lang/Class' = 'Bar')} 0x000000010649b236: mov 0x70(%r10),%r10d 0x000000010649b23a: add 0xc(%rsi),%r10d 0x000000010649b23e: mov %edx,%eax 0x000000010649b240: add %r10d,%eax ;*iadd ; - Bar::sum@9 (line 5) 0x000000010649b243: add $0x10,%rsp 0x000000010649b247: pop %rbp 0x000000010649b248: test %eax,-0x8ac24e(%rip) # 0x0000000105bef000 ; {poll_return} 0x000000010649b24e: retq 0x000000010649b24f: hlt 0x000000010649b250: hlt 0x000000010649b251: hlt 0x000000010649b252: hlt 0x000000010649b253: hlt 0x000000010649b254: hlt 0x000000010649b255: hlt 0x000000010649b256: hlt 0x000000010649b257: hlt 0x000000010649b258: hlt 0x000000010649b259: hlt 0x000000010649b25a: hlt 0x000000010649b25b: hlt 0x000000010649b25c: hlt 0x000000010649b25d: hlt 0x000000010649b25e: hlt 0x000000010649b25f: hlt [Exception Handler] [Stub Code] 0x000000010649b260: jmpq 0x00000001064980a0 ; {no_reloc} [Deopt Handler Code] 0x000000010649b265: callq 0x000000010649b26a 0x000000010649b26a: subq $0x5,(%rsp) 0x000000010649b26f: jmpq 0x0000000106471b00 ; {runtime_call} 0x000000010649b274: hlt 0x000000010649b275: hlt 0x000000010649b276: hlt 0x000000010649b277: hlt
想了解具体的指令是啥含义,可以参考这篇文章JVM执行篇:使用HSDIS插件分析JVM代码执行细节