2013-02-05 37 views
7

這是關於Java優化的一個非常基本的問題。Java優化器和冗餘陣列評估

如果你有一個簡單的for循環遍歷一個數組,並在循環的頭部使用array.length,而不是在之前對它進行評估,所以你只做一次(這是我幾乎總是這樣做的):

for(int i=0; i<array.length;i++) { ... } 

能否語句優化,使得JVM知道數組是否正在改變循環的持續時間,以便它不會重新評估每一次array.length

+6

陣列具有固定長度。 –

+0

但是'array'可以重新分配給循環內具有不同長度的不同數組。 – iamnotmaynard

+0

你可能會問'ArrayList'。 –

回答

9

如果另一個線程不會修改陣列的同時,將array.length能夠得到有效評估一次,

更關鍵的是,除非該字段爲volatile JVM將做這樣的假設是否屬實或不。

+0

因此,您所說的除非是volatile,沒有太大的性能差異 – amphibient

+0

是的,但除非代碼被迭代10,000次,否則不會被編譯爲本地代碼,這將產生更大的差異。 –

+1

這麼長的故事總之,在循環之前評估它是爲了安全起見。謝謝 – amphibient

2

Java中的數組是固定長度的。創建數組後,長度無法更改。首先獲取長度並將其分配給局部變量沒有任何優勢。

2

花費了太多的時間調試之後,我得到:

答:

static String test(String[] arg){ 
    String a =""; 
    for(int i = 0, len = arg.length; i < len; i++) 
     if (arg[i].length() > a.length()) a = arg[i]; 
    return a; 
    } 

B:

static String test(String[] arg){ 
    String a =""; 
    for(int i = 0; i < arg.length; i++) 
     if (arg[i].length() > a.length()) a = arg[i]; 
    return a; 
    } 

字節碼:

static java.lang.String test(java.lang.String[]); 
    Code: 
    0: ldC#2; //String 
    2: astore_1 
    3: iconst_0 
    4: istore_2 
    5: aload_0 
    6: arraylength 
    7: istore_3 
    8: iload_2 
    9: iload_3 
    10: if_icmpge 36 
    13: aload_0 
    14: iload_2 
    15: aaload 
    16: invokevirtual #3; //Method java/lang/String.length:()I 
    19: aload_1 
    20: invokevirtual #3; //Method java/lang/String.length:()I 
    23: if_icmple 30 
    26: aload_0 
    27: iload_2 
    28: aaload 
    29: astore_1 
    30: iinc 2, 1 
    33: goto 8 
    36: aload_1 
    37: areturn 

乙字節碼:

static java.lang.String test(java.lang.String[]); 
    Code: 
    0: ldC#2; //String 
    2: astore_1 
    3: iconst_0 
    4: istore_2 
    5: iload_2 
    6: aload_0 
    7: arraylength 
    8: if_icmpge 34 
    11: aload_0 
    12: iload_2 
    13: aaload 
    14: invokevirtual #3; //Method java/lang/String.length:()I 
    17: aload_1 
    18: invokevirtual #3; //Method java/lang/String.length:()I 
    21: if_icmple 28 
    24: aload_0 
    25: iload_2 
    26: aaload 
    27: astore_1 
    28: iinc 2, 1 
    31: goto 5 
    34: aload_1 
    35: areturn 

重要的區別是第33/31行,其中goto跳轉到第8行或第5行。在(A)之前和(B)之後調用arraylength。

因此,如果不緩存字節碼,實際上在每次迭代中都會調用arraylength。

當然javac不會優化,只有JIT。 那麼JIT做了什麼?

通常沒有它看起來。它沒有在編譯方法的-XX:+ PrintCompilation列表中列出。

只有調用函數100萬次後,它激活並展開了循環完全去除長度檢查,如果我正確讀取:

拆卸:

# parm0: rsi:rsi = '[Ljava/lang/String;' 
    #   [sp+0x30] (sp of caller) 
    0x00007fdc296b30a0: mov %eax,-0x6000(%rsp) 
    0x00007fdc296b30a7: push %rbp 
    0x00007fdc296b30a8: sub $0x20,%rsp   ;*synchronization entry 
               ; - Acminesimple::[email protected] (line 3) 
    0x00007fdc296b30ac: mov 0xc(%rsi),%ebp  ;*arraylength 
               ; - Acminesimple::[email protected] (line 4) 
               ; implicit exception: dispatches to 0x00007fdc296b31ad 
    0x00007fdc296b30af: movabs $0xeb8b7168,%rax ; {oop("")} 
    0x00007fdc296b30b9: test %ebp,%ebp 
    0x00007fdc296b30bb: jle 0x00007fdc296b312e ;*if_icmpge 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b30bd: test %ebp,%ebp 
    0x00007fdc296b30bf: jbe 0x00007fdc296b3177 
    0x00007fdc296b30c5: mov %ebp,%ecx 
    0x00007fdc296b30c7: dec %ecx 
    0x00007fdc296b30c9: cmp %ebp,%ecx 
    0x00007fdc296b30cb: jae 0x00007fdc296b3177 
    0x00007fdc296b30d1: xor %r8d,%r8d   ;*aload_0 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b30d4: mov 0x10(%rsi,%r8,4),%edi ;*aaload 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b30d9: mov 0x14(%rdi),%r11d ; implicit exception: dispatches to 0x00007fdc296b318d 
    0x00007fdc296b30dd: mov 0x14(%rax),%r10d ; implicit exception: dispatches to 0x00007fdc296b319d 
    0x00007fdc296b30e1: cmp %r10d,%r11d 
    0x00007fdc296b30e4: jg  0x00007fdc296b30e9 ;*if_icmple 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b30e6: mov %rax,%rdi 
    0x00007fdc296b30e9: inc %r8d    ;*iinc 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b30ec: cmp $0x1,%r8d 
    0x00007fdc296b30f0: jge 0x00007fdc296b30f7 ;*if_icmpge 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b30f2: mov %rdi,%rax   ;*iinc 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b30f5: jmp 0x00007fdc296b30d4 
    0x00007fdc296b30f7: cmp %ecx,%r8d 
    0x00007fdc296b30fa: jl  0x00007fdc296b3163 
    0x00007fdc296b30fc: mov %edi,%r10d 
    0x00007fdc296b30ff: cmp %ebp,%r8d 
    0x00007fdc296b3102: jl  0x00007fdc296b310f 
    0x00007fdc296b3104: mov %r10d,%r9d 
    0x00007fdc296b3107: jmp 0x00007fdc296b312b 
    0x00007fdc296b3109: data32 xchg %ax,%ax 
    0x00007fdc296b310c: mov %r9d,%r10d   ;*aload_0 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b310f: mov 0x10(%rsi,%r8,4),%r9d ;*aaload 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b3114: mov 0x14(%r9),%r11d ; implicit exception: dispatches to 0x00007fdc296b318d 
    0x00007fdc296b3118: mov 0x14(%r10),%ebx ; implicit exception: dispatches to 0x00007fdc296b319d 
    0x00007fdc296b311c: cmp %ebx,%r11d 
    0x00007fdc296b311f: cmovle %r10d,%r9d 
    0x00007fdc296b3123: inc %r8d    ;*iinc 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b3126: cmp %ebp,%r8d 
    0x00007fdc296b3129: jl  0x00007fdc296b310c 
    0x00007fdc296b312b: mov %r9,%rax   ;*if_icmpge 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b312e: add $0x20,%rsp 
    0x00007fdc296b3132: pop %rbp 
    0x00007fdc296b3133: test %eax,0x5766ec7(%rip)  # 0x00007fdc2ee1a000 
               ; {poll_return} 
    0x00007fdc296b3139: retq 
    0x00007fdc296b313a: mov %r11d,%edi 
    0x00007fdc296b313d: data32 xchg %ax,%ax  ;*iinc 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b3140: movslq %r8d,%r10 
    0x00007fdc296b3143: mov 0x14(%rsi,%r10,4),%r10d ;*aaload 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b3148: mov 0x14(%r10),%r9d ; implicit exception: dispatches to 0x00007fdc296b318d 
    0x00007fdc296b314c: mov 0x14(%rdi),%r11d ; implicit exception: dispatches to 0x00007fdc296b319d 
    0x00007fdc296b3150: cmp %r11d,%r9d 
    0x00007fdc296b3153: cmovle %edi,%r10d 
    0x00007fdc296b3157: add $0x2,%r8d   ;*iinc 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b315b: cmp %ecx,%r8d 
    0x00007fdc296b315e: jge 0x00007fdc296b30ff ;*if_icmpge 
               ; - Acminesimple::[email protected] (line 4) 
    0x00007fdc296b3160: mov %r10d,%edi   ;*aload_0 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b3163: mov 0x10(%rsi,%r8,4),%r11d ;*aaload 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b3168: mov 0x14(%r11),%r10d ; implicit exception: dispatches to 0x00007fdc296b318d 
    0x00007fdc296b316c: mov 0x14(%rdi),%r9d ; implicit exception: dispatches to 0x00007fdc296b319d 
    0x00007fdc296b3170: cmp %r9d,%r10d 
               ; - Acminesimple::[email protected] (line 5) 
    0x00007fdc296b3175: jmp 0x00007fdc296b3140 
    0x00007fdc296b3177: mov %rsi,(%rsp) 
    0x00007fdc296b317b: mov $0xffffff86,%esi 
    0x00007fdc296b3180: data32 xchg %ax,%ax 
    0x00007fdc296b3183: callq 0x00007fdc29620320 ; OopMap{[0]=Oop off=232} 
               ;*aload_0 
               ; - Acminesimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fdc296b3188: callq 0x00007fdc2de8b7c0 ;*aload_0 
               ; - Acminesimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fdc296b318d: mov $0xfffffff6,%esi 
    0x00007fdc296b3192: nop 
    0x00007fdc296b3193: callq 0x00007fdc29620320 ; OopMap{off=248} 
               ;*invokevirtual length 
               ; - Acminesimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fdc296b3198: callq 0x00007fdc2de8b7c0 ;*invokevirtual length 
               ; - Acminesimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fdc296b319d: mov $0xfffffff6,%esi 
    0x00007fdc296b31a2: nop 
    0x00007fdc296b31a3: callq 0x00007fdc29620320 ; OopMap{off=264} 
               ;*invokevirtual length 
               ; - Acminesimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fdc296b31a8: callq 0x00007fdc2de8b7c0 ;*invokevirtual length 
               ; - Acminesimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fdc296b31ad: mov $0xfffffff6,%esi 
    0x00007fdc296b31b2: nop 
    0x00007fdc296b31b3: callq 0x00007fdc29620320 ; OopMap{off=280} 
               ;*arraylength 
               ; - Acminesimple::[email protected] (line 4) 
               ; {runtime_call} 
    0x00007fdc296b31b8: callq 0x00007fdc2de8b7c0 ;*arraylength 
               ; - Acminesimple::[email protected] (line 4) 
               ; {runtime_call} 
    0x00007fdc296b31bd: hlt  
    0x00007fdc296b31be: hlt  
    0x00007fdc296b31bf: hlt  
[Exception Handler] 

乙拆解:

# parm0: rsi:rsi = '[Ljava/lang/String;' 
    #   [sp+0x20] (sp of caller) 
    0x00007fc749ebcf20: mov %eax,-0x6000(%rsp) 
    0x00007fc749ebcf27: push %rbp 
    0x00007fc749ebcf28: sub $0x10,%rsp   ;*synchronization entry 
               ; - Acfoamsimple::[email protected] (line 3) 
    0x00007fc749ebcf2c: mov 0xc(%rsi),%r9d  ;*arraylength 
               ; - Acfoamsimple::[email protected] (line 4) 
               ; implicit exception: dispatches to 0x00007fc749ebd029 
    0x00007fc749ebcf30: movabs $0xeb8b7168,%rax ; {oop("")} 
    0x00007fc749ebcf3a: test %r9d,%r9d 
    0x00007fc749ebcf3d: jle 0x00007fc749ebcfad ;*if_icmpge 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcf3f: test %r9d,%r9d 
    0x00007fc749ebcf42: jbe 0x00007fc749ebcff5 
    0x00007fc749ebcf48: mov %r9d,%ebx 
    0x00007fc749ebcf4b: dec %ebx 
    0x00007fc749ebcf4d: cmp %r9d,%ebx 
    0x00007fc749ebcf50: jae 0x00007fc749ebcff5 
    0x00007fc749ebcf56: xor %ecx,%ecx   ;*aload_0 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcf58: mov 0x10(%rsi,%rcx,4),%edx ;*aaload 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcf5c: mov 0x14(%rdx),%r10d ; implicit exception: dispatches to 0x00007fc749ebd009 
    0x00007fc749ebcf60: mov 0x14(%rax),%r8d ; implicit exception: dispatches to 0x00007fc749ebd019 
    0x00007fc749ebcf64: cmp %r8d,%r10d 
    0x00007fc749ebcf67: jg  0x00007fc749ebcf6c ;*if_icmple 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcf69: mov %rax,%rdx 
    0x00007fc749ebcf6c: inc %ecx    ;*iinc 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcf6e: cmp $0x1,%ecx 
    0x00007fc749ebcf71: jge 0x00007fc749ebcf78 ;*if_icmpge 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcf73: mov %rdx,%rax   ;*iinc 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcf76: jmp 0x00007fc749ebcf58 
    0x00007fc749ebcf78: cmp %ebx,%ecx 
    0x00007fc749ebcf7a: jl  0x00007fc749ebcfe1 
    0x00007fc749ebcf7c: mov %edx,%r10d 
    0x00007fc749ebcf7f: cmp %r9d,%ecx 
    0x00007fc749ebcf82: jl  0x00007fc749ebcf8f 
    0x00007fc749ebcf84: mov %r10d,%r8d 
    0x00007fc749ebcf87: jmp 0x00007fc749ebcfaa 
    0x00007fc749ebcf89: data32 xchg %ax,%ax 
    0x00007fc749ebcf8c: mov %r8d,%r10d   ;*aload_0 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcf8f: mov 0x10(%rsi,%rcx,4),%r8d ;*aaload 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcf94: mov 0x14(%r8),%r11d ; implicit exception: dispatches to 0x00007fc749ebd009 
    0x00007fc749ebcf98: mov 0x14(%r10),%edi ; implicit exception: dispatches to 0x00007fc749ebd019 
    0x00007fc749ebcf9c: cmp %edi,%r11d 
    0x00007fc749ebcf9f: cmovle %r10d,%r8d 
    0x00007fc749ebcfa3: inc %ecx    ;*iinc 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcfa5: cmp %r9d,%ecx 
    0x00007fc749ebcfa8: jl  0x00007fc749ebcf8c 
    0x00007fc749ebcfaa: mov %r8,%rax   ;*if_icmpge 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcfad: add $0x10,%rsp 
    0x00007fc749ebcfb1: pop %rbp 
    0x00007fc749ebcfb2: test %eax,0x5766048(%rip)  # 0x00007fc74f623000 
               ; {poll_return} 
    0x00007fc749ebcfb8: retq 
    0x00007fc749ebcfb9: mov %r10d,%edx 
    0x00007fc749ebcfbc: nopl 0x0(%rax)   ;*iinc 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcfc0: movslq %ecx,%r10 
    0x00007fc749ebcfc3: mov 0x14(%rsi,%r10,4),%r10d ;*aaload 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcfc8: mov 0x14(%r10),%r8d ; implicit exception: dispatches to 0x00007fc749ebd009 
    0x00007fc749ebcfcc: mov 0x14(%rdx),%r11d ; implicit exception: dispatches to 0x00007fc749ebd019 
    0x00007fc749ebcfd0: cmp %r11d,%r8d 
    0x00007fc749ebcfd3: cmovle %edx,%r10d 
    0x00007fc749ebcfd7: add $0x2,%ecx   ;*iinc 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcfda: cmp %ebx,%ecx 
    0x00007fc749ebcfdc: jge 0x00007fc749ebcf7f ;*if_icmpge 
               ; - Acfoamsimple::[email protected] (line 4) 
    0x00007fc749ebcfde: mov %r10d,%edx   ;*aload_0 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcfe1: mov 0x10(%rsi,%rcx,4),%r10d ;*aaload 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcfe6: mov 0x14(%r10),%r8d ; implicit exception: dispatches to 0x00007fc749ebd009 
    0x00007fc749ebcfea: mov 0x14(%rdx),%r11d ; implicit exception: dispatches to 0x00007fc749ebd019 
    0x00007fc749ebcfee: cmp %r11d,%r8d 
    0x00007fc749ebcff1: jg  0x00007fc749ebcfb9 ;*if_icmple 
               ; - Acfoamsimple::[email protected] (line 5) 
    0x00007fc749ebcff3: jmp 0x00007fc749ebcfc0 
    0x00007fc749ebcff5: mov %rsi,%rbp 
    0x00007fc749ebcff8: mov $0xffffff86,%esi 
    0x00007fc749ebcfff: callq 0x00007fc749e29320 ; OopMap{rbp=Oop off=228} 
               ;*aload_0 
               ; - Acfoamsimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fc749ebd004: callq 0x00007fc74e6947c0 ;*aload_0 
               ; - Acfoamsimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fc749ebd009: mov $0xfffffff6,%esi 
    0x00007fc749ebd00e: nop 
    0x00007fc749ebd00f: callq 0x00007fc749e29320 ; OopMap{off=244} 
               ;*invokevirtual length 
               ; - Acfoamsimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fc749ebd014: callq 0x00007fc74e6947c0 ;*invokevirtual length 
               ; - Acfoamsimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fc749ebd019: mov $0xfffffff6,%esi 
    0x00007fc749ebd01e: nop 
    0x00007fc749ebd01f: callq 0x00007fc749e29320 ; OopMap{off=260} 
               ;*invokevirtual length 
               ; - Acfoamsimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fc749ebd024: callq 0x00007fc74e6947c0 ;*invokevirtual length 
               ; - Acfoamsimple::[email protected] (line 5) 
               ; {runtime_call} 
    0x00007fc749ebd029: mov $0xfffffff6,%esi 
    0x00007fc749ebd02e: nop 
    0x00007fc749ebd02f: callq 0x00007fc749e29320 ; OopMap{off=276} 
               ;*arraylength 
               ; - Acfoamsimple::[email protected] (line 4) 
               ; {runtime_call} 
    0x00007fc749ebd034: callq 0x00007fc74e6947c0 ;*arraylength 
               ; - Acfoamsimple::[email protected] (line 4) 
               ; {runtime_call} 
    0x00007fc749ebd039: hlt  
    0x00007fc749ebd03a: hlt  
    0x00007fc749ebd03b: hlt  
    0x00007fc749ebd03c: hlt  
    0x00007fc749ebd03d: hlt  
    0x00007fc749ebd03e: hlt  
    0x00007fc749ebd03f: hlt  

使用Math.min(args.length, 20),而不是像args.lengthdiscussion starting question,它的行爲類似:

A-與分鐘:

static java.lang.String test(java.lang.String[]); 
    Code: 
    0: ldC#2; //String 
    2: astore_1 
    3: iconst_0 
    4: istore_2 
    5: aload_0 
    6: arraylength 
    7: bipush 20 
    9: invokestatic #3; //Method java/lang/Math.min:(II)I 
    12: istore_3 
    13: iload_2 
    14: iload_3 
    15: if_icmpge 41 
    18: aload_0 
    19: iload_2 
    20: aaload 
    21: invokevirtual #4; //Method java/lang/String.length:()I 
    24: aload_1 
    25: invokevirtual #4; //Method java/lang/String.length:()I 
    28: if_icmple 35 
    31: aload_0 
    32: iload_2 
    33: aaload 
    34: astore_1 
    35: iinc 2, 1 
    38: goto 13 
    41: aload_1 
    42: areturn 

B-與敏:

static java.lang.String test(java.lang.String[]); 
    Code: 
    0: ldC#2; //String 
    2: astore_1 
    3: iconst_0 
    4: istore_2 
    5: iload_2 
    6: aload_0 
    7: arraylength 
    8: bipush 20 
    10: invokestatic #3; //Method java/lang/Math.min:(II)I 
    13: if_icmpge 39 
    16: aload_0 
    17: iload_2 
    18: aaload 
    19: invokevirtual #4; //Method java/lang/String.length:()I 
    22: aload_1 
    23: invokevirtual #4; //Method java/lang/String.length:()I 
    26: if_icmple 33 
    29: aload_0 
    30: iload_2 
    31: aaload 
    32: astore_1 
    33: iinc 2, 1 
    36: goto 5 
    39: aload_1 
    40: areturn 

(JIT拆卸功能太長在回答後)

+0

你是如何得到所有這些輸出的? – amphibient

+1

非常緩慢,這就是一直吃的東西。字節碼部分很簡單:'javap -c classname',jit反彙編器就像'java -server -XX:+ UnlockDiagnosticVMOptions'-XX:CompileCommand = print,* classname.methodname'-XX:CompileThreshold = 10 -cp。 classname'。但它只能打印出一些東西,如果它真的被編譯的話。你應該安裝hsdis插件。 – BeniBela

+0

這只是確認'arraylength'只是引用數組中的一個字段。在這兩種情況下,將數組長度轉換爲「mov」指令。 –