16

今日、私は入門プログラミング コースを教えていて、Java での変数の割り当てを含むいくつかの簡単なコードについて説明していました。コードのポイントは、何か特別なことを見せびらかすことではなく、学生が変数代入ステートメントを確実に理解できるようにすることでした。

ボード上に次のメソッドがあり、一度に 1 行ずつトレースしていました。

private void simpleMethod() {
    int myInt = 137;
    myInt = 42;
    myInt = myInt + 1;

    /* ... code using myInt ... */
}

学生からmyInt、プログラムの実行時に値 137 と 42 が実際に保持されるのか、それとも 43 を保持するようにジャンプするのかと尋ねられました。私は学生に、コードは各行を順番に実行するので、変数は実際に保持されると言いました。これらの中間値。

正直なところ、バイトコードが何を出力するかはわかりませんでしたjavac(JVM による最適化を完全に無視していました)。(または任意の Java コンパイラ)は、ばかげた割り当てステートメントを最適化し、代わりに 43javacに直接初期化することを法的に許可されていますか?myInt

によるとjavap、私のシステムでは、上記のコードでコンパイルするとjavac生成されます

   0: sipush        137
   3: istore_1      
   4: bipush        42
   6: istore_1      
   7: iload_1       
   8: iconst_1      
   9: iadd          
  10: istore_1      
  11: return        

したがって、ここでは最適化は行われません。ただし、私の質問は、これを最適化することが合法かどうかであり、これは何も解決しません。

4

4 に答える 4

8

JLS は、プログラムが生成する観察可能な動作の契約のみを指定します。はローカルであるためmyInt、最適化は実際にコンパイル時に最適化できます。これにより、仕様と一致する動作が生成され、仕様には許可されていないと書かれているものは何もありません (少なくとも、私が見つけたものではありません!)。仕様の第 1 章では、仕様の可観測性を明示的に指定していますThis document fully specifies the (apparent) order of evaluation of expressions...。への定数フォールディングによって見た目の動作が変わらないためmyInt = 43、最適化は JLS と一致します。

実際、Java アプリケーションのコンパイル ターゲットは、JLS では指定されていません。第 1 章では、Java アプリケーションは「通常」、JVM 仕様 (別のドキュメント) で指定されたバイトコードにコンパイルされると述べていますが、そうする必要はありません。コンパイル時に最適化する必要あるステートメントがいくつかありますが、そのようなものではありません。フィールドだったとしても、最適化は許可されると思います。揮発性であっても、異なる動作は依然として有効な動作です(イベントの 1 つの有効な順序を表すため)。myIntmyIntmyInt

ですから、短い答えですが、あなたの学生は正しいと思います。に最適化してもまったく問題ありませんmyInt = 43。とは言っjavacても、最適化の方法では、一般的にほとんど何もしません。最適化はほとんどすべて JIT で行われます。

于 2013-01-15T07:59:57.117 に答える
5

Java コンパイラーは、コンパイル時に静的に決定できる定数の折り畳みを行うことが許可されていると思います。

はい、これはによって最適化できjavacます。

ただし、この最適化javac を行う必要はありません。これは、JVM JIT コンパイラがほぼ確実に同じ最適化を行うためです。その観点からすると、Java -> Bytecode コンパイラーがこの最適化を行うかどうかは、実行時に実行される実際のネイティブ コードへの影響という点ではおそらく無関係です。

于 2013-01-15T07:06:14.017 に答える
0

したがって、ここでは最適化は行われていません。

Javaが動的コンパイルを使用していることを考えると、これはそれほど驚くべきことではありません。

JVMは実行時にほぼすべてのコードを最適化します。つまり、1996年にJava 1.0用にコンパイルされたコードを使用するか、ScalaまたはJRuby、JGoなどを使用するかに関係なく、特定のCPUモデルのネイティブコードに対する最適化のメリットを最大限に活用できます。

このため、多くの言語にはJVMが実装されているため、JVMが実行されているすべてのプラットフォームに最適なコードを生成できる必要はありません。

于 2013-01-15T08:09:31.920 に答える
0

これは本当ですが、私の質問は、コンパイラがこの最適化を行うことを法的に許可されているかどうかです

従来のデータフロー分析 (フロー/伝達関数、インセット、アウトセット、ジェネセット、キルセットなど)、具体的にはデータフローを転送するいくつかのパス、別名到達定義 (または use-def チェーン) によって。 .. はい。基本的に、オプティマイザーは、変数の各使用をそれに到達する定義にリンクできます。

この場合、オプティマイザーは、 myInt の最初の定義 (=137) が使用に達することはないと判断できますが、他の定義 (=42 1 ) は、その定義からの (一部の) パスで再定義されないため、使用に達します。その使用に。

参考文献:

  • ドラゴンブック1ed(1986)第10章
  • ドラゴンブック2ed(2007)第9章(具体的には9.2)

1 - 私は教育コードで常に 42 を使用しています。私たち全員がそうするに違いない。

于 2013-01-15T15:58:59.067 に答える