JVM中的方法内联
在C++中,可以明确定义内联函数,使用inline关键字。在Java中不能定义内联函数,但是方法的内联在JIT编译中还是存在的,只不过是JIT自动优化的,我们无法在写代码的时候指定。
所谓内联函数就是指函数在被调用的地方直接展开,编译器在调用时不用像一般函数那样,参数压栈,返回时参数出栈以及资源释放等,这样提高了程序执行速度。 一般函数的调用时,JVM会自动新建一个堆栈框架来处理参数和下一条指令的地址,当执行完函数调用后再撤销该堆栈。
public class Test {public static void foo() { boolean t = true;boolean f = false;System.out.println(t == f);} public static void main(String[] args) { foo(); }}javap -c -s -l -verbose Test
public static void foo(); Signature: ()V LineNumberTable: line 5: 0 line 6: 2 line 7: 4 line 8: 20 LocalVariableTable: Start Length Slot Name Signature 2 19 0 t Z 4 17 1 f Z Code: Stack=3, Locals=2, Args_size=0 0: iconst_1 1: istore_0 2: iconst_0 3: istore_1 4: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream; 7: iload_0 8: iload_1 9: if_icmpne 16 12: iconst_1 13: goto 17 16: iconst_0 17: invokevirtual #21; //Method java/io/PrintStream.println:(Z)V 20: return LineNumberTable: line 5: 0 line 6: 2 line 7: 4 line 8: 20 LocalVariableTable: Start Length Slot Name Signature 2 19 0 t Z 4 17 1 f Z StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 16 locals = [ int, int ] stack = [ class java/io/PrintStream ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ int, int ] stack = [ class java/io/PrintStream, int ]public static void main(java.lang.String[]); Signature: ([Ljava/lang/String;)V LineNumberTable: line 11: 0 line 12: 3 LocalVariableTable: Start Length Slot Name Signature 0 4 0 args [Ljava/lang/String; Code: Stack=0, Locals=1, Args_size=1 0: invokestatic #33; //Method foo:()V 3: return LineNumberTable: line 11: 0 line 12: 3 LocalVariableTable: Start Length Slot Name Signature 0 4 0 args [Ljava/lang/String;
java -Xrunhprof:cpu=times InlineMe
-XX:+PrintInlining
@ 0 org.dothwinds.test.Test::foo (21 bytes)
Code: Stack=3, Locals=2, Args_size=0 0: iconst_1 1: istore_0 2: iconst_0 3: istore_1 4: getstatic #15; //Field java/lang/System.out:Ljava/io/PrintStream; 7: iload_0 8: iload_1 9: if_icmpne 16 12: iconst_1 13: goto 17 16: iconst_0 17: invokevirtual #21; //Method java/io/PrintStream.println:(Z)V 20: return
java -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly org/dothwinds/test/Test >log.log
Code:[Disassembling for mach='i386'][Entry Point][Verified Entry Point][Constants] # {method} 'main' '([Ljava/lang/String;)V' in 'org/dothwinds/test/Test' # parm0: ecx = '[Ljava/lang/String;' # [sp+0x20] (sp of caller) ;; block B6 [0, 0] 0x01cd3930: mov %eax,-0x8000(%esp) 0x01cd3937: push %ebp 0x01cd3938: sub $0x18,%esp ;*invokestatic foo ; - org.dothwinds.test.Test::main@0 (line 11) ;; block B0 [0, 3] ;; 10 move [obj:0x0|L] [edx|L] [patch_normal] [bci:4] 0x01cd393b: nop 0x01cd393c: nop 0x01cd393d: nop 0x01cd393e: nop 0x01cd393f: nop 0x01cd3940: jmp 0x01cd3990 ; {no_reloc} ;; 12 move [Base:[edx|L] Disp: 2147483647|L] [ecx|L] [patch_normal] [bci:4] 0x01cd3945: nop 0x01cd3946: nop 0x01cd3947: nop 0x01cd3948: jmp 0x01cd39bb ; implicit exception: dispatches to 0x01cd399a 0x01cd394d: nop ;*getstatic out ; - org.dothwinds.test.Test::foo@4 (line 7) ; - org.dothwinds.test.Test::main@0 (line 11) 0x01cd394e: cmp (%ecx),%eax ; implicit exception: dispatches to 0x01cd39c5 0x01cd3950: mov $0x0,%edx ;*invokevirtual println ; - org.dothwinds.test.Test::foo@17 (line 7) ; - org.dothwinds.test.Test::main@0 (line 11) 0x01cd3955: nop 0x01cd3956: mov $0xffffffff,%eax ; {oop(NULL)} 0x01cd395b: call 0x01c0b210 ; OopMap{off=48} ;*invokevirtual println ; - org.dothwinds.test.Test::foo@17 (line 7) ; - org.dothwinds.test.Test::main@0 (line 11) ; {virtual_call} 0x01cd3960: add $0x18,%esp 0x01cd3963: pop %ebp 0x01cd3964: test %eax,0x260100 ; {poll_return} 0x01cd396a: ret 0x01cd395b: call 0x01c0b210 ; OopMap{off=48} ;*invokevirtual println ; - org.dothwinds.test.Test::foo@17 (line 7) ; - org.dothwinds.test.Test::main@0 (line 11) ; {virtual_call}-XX:CompileCommand=dontinline,org/dothwinds/test/Test,foo