Java优化器和冗余arrays评估

这是关于Java优化的一个非常基本的问题。

如果你有一个简单的for循环迭代数组并在循环的头部使用array.length而不是之前评估它,那么你只做一次(这是我几乎总是这样做):

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

可以对语句进行优化,以便JVM知道数组是否在循环的持续时间内发生变化,这样它每次都不会重新评估array.length吗?

如果另一个线程没有同时修改数组,那么array.length只能被有效地评估一次,

更重要的是,除非该字段是volatile的,否则JVM将做出这种假设,无论它是否真实。

Java中的数组是固定长度的。 创建数组后,无法更改长度。 首先抓取长度并将其分配给局部变量没有任何好处。

花了太多时间调试这个后,我得到了:

A:

  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 

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: 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::test@-1 (line 3) 0x00007fdc296b30ac: mov 0xc(%rsi),%ebp ;*arraylength ; - Acminesimple::test@6 (line 4) ; implicit exception: dispatches to 0x00007fdc296b31ad 0x00007fdc296b30af: movabs $0xeb8b7168,%rax ; {oop("")} 0x00007fdc296b30b9: test %ebp,%ebp 0x00007fdc296b30bb: jle 0x00007fdc296b312e ;*if_icmpge ; - Acminesimple::test@10 (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::test@13 (line 5) 0x00007fdc296b30d4: mov 0x10(%rsi,%r8,4),%edi ;*aaload ; - Acminesimple::test@15 (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::test@23 (line 5) 0x00007fdc296b30e6: mov %rax,%rdi 0x00007fdc296b30e9: inc %r8d ;*iinc ; - Acminesimple::test@30 (line 4) 0x00007fdc296b30ec: cmp $0x1,%r8d 0x00007fdc296b30f0: jge 0x00007fdc296b30f7 ;*if_icmpge ; - Acminesimple::test@10 (line 4) 0x00007fdc296b30f2: mov %rdi,%rax ;*iinc ; - Acminesimple::test@30 (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::test@13 (line 5) 0x00007fdc296b310f: mov 0x10(%rsi,%r8,4),%r9d ;*aaload ; - Acminesimple::test@15 (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::test@30 (line 4) 0x00007fdc296b3126: cmp %ebp,%r8d 0x00007fdc296b3129: jl 0x00007fdc296b310c 0x00007fdc296b312b: mov %r9,%rax ;*if_icmpge ; - Acminesimple::test@10 (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::test@30 (line 4) 0x00007fdc296b3140: movslq %r8d,%r10 0x00007fdc296b3143: mov 0x14(%rsi,%r10,4),%r10d ;*aaload ; - Acminesimple::test@15 (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::test@30 (line 4) 0x00007fdc296b315b: cmp %ecx,%r8d 0x00007fdc296b315e: jge 0x00007fdc296b30ff ;*if_icmpge ; - Acminesimple::test@10 (line 4) 0x00007fdc296b3160: mov %r10d,%edi ;*aload_0 ; - Acminesimple::test@13 (line 5) 0x00007fdc296b3163: mov 0x10(%rsi,%r8,4),%r11d ;*aaload ; - Acminesimple::test@15 (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::test@23 (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::test@13 (line 5) ; {runtime_call} 0x00007fdc296b3188: callq 0x00007fdc2de8b7c0 ;*aload_0 ; - Acminesimple::test@13 (line 5) ; {runtime_call} 0x00007fdc296b318d: mov $0xfffffff6,%esi 0x00007fdc296b3192: nop 0x00007fdc296b3193: callq 0x00007fdc29620320 ; OopMap{off=248} ;*invokevirtual length ; - Acminesimple::test@16 (line 5) ; {runtime_call} 0x00007fdc296b3198: callq 0x00007fdc2de8b7c0 ;*invokevirtual length ; - Acminesimple::test@16 (line 5) ; {runtime_call} 0x00007fdc296b319d: mov $0xfffffff6,%esi 0x00007fdc296b31a2: nop 0x00007fdc296b31a3: callq 0x00007fdc29620320 ; OopMap{off=264} ;*invokevirtual length ; - Acminesimple::test@20 (line 5) ; {runtime_call} 0x00007fdc296b31a8: callq 0x00007fdc2de8b7c0 ;*invokevirtual length ; - Acminesimple::test@20 (line 5) ; {runtime_call} 0x00007fdc296b31ad: mov $0xfffffff6,%esi 0x00007fdc296b31b2: nop 0x00007fdc296b31b3: callq 0x00007fdc29620320 ; OopMap{off=280} ;*arraylength ; - Acminesimple::test@6 (line 4) ; {runtime_call} 0x00007fdc296b31b8: callq 0x00007fdc2de8b7c0 ;*arraylength ; - Acminesimple::test@6 (line 4) ; {runtime_call} 0x00007fdc296b31bd: hlt 0x00007fdc296b31be: hlt 0x00007fdc296b31bf: hlt [Exception Handler] 

B拆解:

 # 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::test@-1 (line 3) 0x00007fc749ebcf2c: mov 0xc(%rsi),%r9d ;*arraylength ; - Acfoamsimple::test@7 (line 4) ; implicit exception: dispatches to 0x00007fc749ebd029 0x00007fc749ebcf30: movabs $0xeb8b7168,%rax ; {oop("")} 0x00007fc749ebcf3a: test %r9d,%r9d 0x00007fc749ebcf3d: jle 0x00007fc749ebcfad ;*if_icmpge ; - Acfoamsimple::test@8 (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::test@11 (line 5) 0x00007fc749ebcf58: mov 0x10(%rsi,%rcx,4),%edx ;*aaload ; - Acfoamsimple::test@13 (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::test@21 (line 5) 0x00007fc749ebcf69: mov %rax,%rdx 0x00007fc749ebcf6c: inc %ecx ;*iinc ; - Acfoamsimple::test@28 (line 4) 0x00007fc749ebcf6e: cmp $0x1,%ecx 0x00007fc749ebcf71: jge 0x00007fc749ebcf78 ;*if_icmpge ; - Acfoamsimple::test@8 (line 4) 0x00007fc749ebcf73: mov %rdx,%rax ;*iinc ; - Acfoamsimple::test@28 (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::test@11 (line 5) 0x00007fc749ebcf8f: mov 0x10(%rsi,%rcx,4),%r8d ;*aaload ; - Acfoamsimple::test@13 (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::test@28 (line 4) 0x00007fc749ebcfa5: cmp %r9d,%ecx 0x00007fc749ebcfa8: jl 0x00007fc749ebcf8c 0x00007fc749ebcfaa: mov %r8,%rax ;*if_icmpge ; - Acfoamsimple::test@8 (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::test@28 (line 4) 0x00007fc749ebcfc0: movslq %ecx,%r10 0x00007fc749ebcfc3: mov 0x14(%rsi,%r10,4),%r10d ;*aaload ; - Acfoamsimple::test@13 (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::test@28 (line 4) 0x00007fc749ebcfda: cmp %ebx,%ecx 0x00007fc749ebcfdc: jge 0x00007fc749ebcf7f ;*if_icmpge ; - Acfoamsimple::test@8 (line 4) 0x00007fc749ebcfde: mov %r10d,%edx ;*aload_0 ; - Acfoamsimple::test@11 (line 5) 0x00007fc749ebcfe1: mov 0x10(%rsi,%rcx,4),%r10d ;*aaload ; - Acfoamsimple::test@13 (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::test@21 (line 5) 0x00007fc749ebcff3: jmp 0x00007fc749ebcfc0 0x00007fc749ebcff5: mov %rsi,%rbp 0x00007fc749ebcff8: mov $0xffffff86,%esi 0x00007fc749ebcfff: callq 0x00007fc749e29320 ; OopMap{rbp=Oop off=228} ;*aload_0 ; - Acfoamsimple::test@11 (line 5) ; {runtime_call} 0x00007fc749ebd004: callq 0x00007fc74e6947c0 ;*aload_0 ; - Acfoamsimple::test@11 (line 5) ; {runtime_call} 0x00007fc749ebd009: mov $0xfffffff6,%esi 0x00007fc749ebd00e: nop 0x00007fc749ebd00f: callq 0x00007fc749e29320 ; OopMap{off=244} ;*invokevirtual length ; - Acfoamsimple::test@14 (line 5) ; {runtime_call} 0x00007fc749ebd014: callq 0x00007fc74e6947c0 ;*invokevirtual length ; - Acfoamsimple::test@14 (line 5) ; {runtime_call} 0x00007fc749ebd019: mov $0xfffffff6,%esi 0x00007fc749ebd01e: nop 0x00007fc749ebd01f: callq 0x00007fc749e29320 ; OopMap{off=260} ;*invokevirtual length ; - Acfoamsimple::test@18 (line 5) ; {runtime_call} 0x00007fc749ebd024: callq 0x00007fc74e6947c0 ;*invokevirtual length ; - Acfoamsimple::test@18 (line 5) ; {runtime_call} 0x00007fc749ebd029: mov $0xfffffff6,%esi 0x00007fc749ebd02e: nop 0x00007fc749ebd02f: callq 0x00007fc749e29320 ; OopMap{off=276} ;*arraylength ; - Acfoamsimple::test@7 (line 4) ; {runtime_call} 0x00007fc749ebd034: callq 0x00007fc74e6947c0 ;*arraylength ; - Acfoamsimple::test@7 (line 4) ; {runtime_call} 0x00007fc749ebd039: hlt 0x00007fc749ebd03a: hlt 0x00007fc749ebd03b: hlt 0x00007fc749ebd03c: hlt 0x00007fc749ebd03d: hlt 0x00007fc749ebd03e: hlt 0x00007fc749ebd03f: hlt 

在讨论开始问题中使用Math.min(args.length, 20)而不是args.length ,它的行为类似:

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反汇编函数太长,无法发布回复)