2

JVM仕様からわかるように、このコードは次のとおりです。

void spin() {
    int i;
    for (i = 0; i < 100; i++) {
        ;    // Loop body is empty
    }
}

次のようにコンパイルする必要があります。

0   iconst_0
1   istore_1
2   goto 8
5   iinc 1 1
8   iload_1
9   bipush 100
11  if_icmplt 5
14  return  

条件チェックif_icmpltはループ本体の後にありますが、自分でコンパイルして javap で表示すると、次のように表示されます。

0:   iconst_0
1:   istore_1
2:   iload_1
3:   bipush  100
5:   if_icmpge       14
8:   iinc    1, 1
11:  goto    2
14:  return

ループ条件はサイクル本体の前です。なぜこれが起こるのですか?

body の後に条件を配置すると、サイクルごとに goto を実行できなくなり、論理的に見えます。では、なぜOracleJDKは別の方法をとっているのでしょうか?

4

3 に答える 3

2

for ループを (JLS セマンティックから) 実装する簡単な方法は次のとおりです。

  1. 初期化
  2. 条件 - false の場合、6 に進みます。
  3. ループ本体
  4. 増分
  5. 2に行く
  6. 終わり

それは実際にあなたの場合にコンパイラが生成したものです:

  1. 初期化

    0:   iconst_0
    1:   istore_1
    
  2. 条件 - false の場合、6 に進みます。

    2:   iload_1
    3:   bipush  100
    5:   if_icmpge       14
    
  3. ループ本体 (空)

  4. 増分

    8:   iinc    1, 1
    
  5. 2に行く

    11:  goto    2
    
  6. 終わり

    14:  return
    

JVM仕様のバージョンは、それを実装する別の方法であり、これも受け入れられます. 回答者が言ったように、通常の VM の JIT コンパイラはこれを再度調べて、とにかく最適化します (十分に関連性がある場合)。そのため、バイトコード レベルでのわずかな最適化は、JIT を持たない JVM に対してのみ重要です。命令ごとにバイトコードを解釈します。それでも、最適化は実際のマシンに固有のものになります。

于 2013-04-11T19:45:01.190 に答える
2

JIT の最適化を改善するためのものではありません。JIT の場合、これらのコード スニペットは同等です。これは、javac で最適化を行う意味がないためです。とにかく JIT 最適化の方がより強力なためです。

于 2013-04-11T11:17:12.747 に答える
1

どちらの方法でも同じ数の命令であり、既に指摘したように、仕様はコンパイラをこの特定のバイトコードに結び付けていません:

コンパイラスピンをコンパイルして...

コンパイラは、最終的な結果が同じである限り、必要なバイトコードにコンパイルすることをほぼ選択できます。

body の後に条件を配置すると、サイクルごとに goto を実行できなくなり、論理的に見えます。では、なぜOracleJDKは別の方法をとっているのでしょうか?

コンパイラのそのビットを書いた人がスイングしない限り、おそらく明確に言うことは不可能ですが、後のJIT最適化を支援することに関係しているように見えるという点で、あなたの理論は正しいと思います。私の唯一の予感 (これは間違っているかもしれません) は、gotoコマンドの配置に関係している可能性があるということです。最初の 6 つの命令が goto なしで論理ブロックとして取得される場合、より良いコードのインライン化の可能性がいくらかあるかもしれません。それらは、コンパイラが実際に生成するバイトコードにあります。もちろん、その特定以来、gotoそのブロック内にしかジャンプできず、論理的な違いはなく、JIT はまったく同じ効果でインライン化できます。最近では、それを解決するのに十分賢いと思いますが、常にそうであるとは限りません。その場合、生成されたコードは適切な回避策を提供します。もちろん、JIT が十分に巧妙に作成されていれば、コードを変更する必要はなかったので、問題は解決しませんでした。

精巧な理論であり、おそらく完全に間違っていますが、それが機能的な違いである場合、それが私の最善の推測です!

もう1つの可能性は、コンパイラのその部分がどのように書かれているか、完全に偶然であり、その理由がまったくないということです(コンパイラの開発者はおそらくコードを正確に実行しようとはしていなかったように)例で行いました。)

于 2013-04-11T11:17:16.010 に答える