7

これは、Java の最適化に関する非常に基本的な質問です。

配列を反復処理する単純な for ループがあり、前に評価するのではなく、ループのヘッダーで array.length を使用して、1 回だけ実行する場合 (これは私がほとんど常に行っていることです):

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

array.lengthステートメントを最適化して、JVM がループ中に配列が変更されているかどうかを認識し、毎回 再評価しないようにすることはできますか?

4

3 に答える 3

9

別のスレッドが配列を同時に変更していない場合、array.lengthは1回だけ効果的に評価されます。

さらに重要なのは、フィールドがvolatileJVMでない限り、それが真であるかどうかにかかわらず、JVMがこの仮定を行うことです。

于 2013-02-05T15:37:08.607 に答える
2

Java の配列は固定長です。アレイの作成後に長さを変更することはできません。最初に長さを取得してローカル変数に割り当てる利点はありません。

于 2013-02-05T15:50:01.347 に答える
2

これをデバッグするのに時間をかけすぎた後、次のようになりました。

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

重要な違いは、goto が 8 行目または 5 行目にジャンプする 33/31 行目です。(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    

ディスカッション開始の questionでlike のMath.min(args.length, 20)代わりに使用すると、同様に動作します。args.length

A-with-min:

 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-with-min:

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逆アセンブル関数が長すぎて回答に投稿できません)

于 2013-02-05T17:17:16.567 に答える