人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

Javaプログラミングの件で質問です。

public class Test {
public static void main(String[] args) {
int a = 0;
a = 3;
a = 4;
System.out.println(a);
}
}

上のプログラムをコンパイルして生成されたclassファイルを逆アセンブルします。

Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0:aload_0
1:invokespecial#1; //Method java/lang/Object."<init>":()V
4:return

public static void main(java.lang.String[]);
Code:
0:iconst_0
1:istore_1
2:iconst_3
3:istore_1
4:iconst_4
5:istore_1
6:getstatic#2; //Field java/lang/System.out:Ljava/io/PrintStream;
9:iload_1
10:invokevirtual#3; //Method java/io/PrintStream.println:(I)V
13:return

}

すると、上のような結果になります。
変数aに対して0,3,4を順番に代入していますので、istore_1が3回出てきますが、そのうち最後のistore_1以外は明らかに無駄な処理です。
0と3の代入については、その値を使うことが無いので、最適化によって処理自体が取り除かれても良さそうな気がするのですが…
このような明らかに無駄と思える処理について、javacが最適化を行わない理由をご存知でしたら、教えてください。

●質問者: aoisome
●カテゴリ:コンピュータ
✍キーワード: Class Class FIELD Java object
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● pahoo
●13ポイント

-O オプションを指定してコンパイルしましたか?

◎質問者からの返答

-Oオプションを指定してもしなくても、出力されるclassファイルは同一であることを確認しています。

使用したコンパイラはjavac 1.6.0_03です。


2 ● angemaries
●26ポイント

最近のjavacは最適化しません。

java2で既にしていなかったように思うのですが、ここの記憶ははっきりしません。

最適化はJITなどの実行環境がそのプラットフォームにあわせて行うべきという思想からです。

◎質問者からの返答

JITが最適化を行うという思想なのですね。

携帯などのJITが無い環境下だと、困りますね。


3 ● ゆーの
●26ポイント

Java コンパイラの設計者でないので推測になります。

当初、クライアントサイドでお手軽処理には使えても、他の用途には遅くて使えないと言われていた Java は、サーバサイド用途で復権して下手な C 言語プログラムよりも速く動くようになりました。これに大きく寄与したのが、最適化処理を行うタイミングを「コンパイル時にスタティックに (AOT)」から「実行時にダイナミックに (JIT)」、とパラダイムチェンジしたことだと理解しています。具体的にはホットスポットの検出と、JIT コンパイラによるネイティブコードへのコンパイルです。

よく実行時間の 8 割はコード全体の 2 割が占めている、などと言ったりしますが、実運用されるようなプログラムにおいては、ほとんどの時間がごくごく一部のコードの処理に費やされていることが容易に想像できます。そのような熱い場所、ホットスポットを検出し、JIT コンパイラでネイティブコードに落としてしまえば、処理全体のほとんどが VM 上のバイトコードの実行ではなく、その CPU 上のネイティブコードで動くことになります。そうなると、ハードウェアレベルのキャッシュにも乗りやすくなり、もしかするとほとんどの時間はキャッシュメモリ内に乗っかってしまう、ということになるかもしれません。

そこまで極端でなくても、AOT コンパイラで最適化に血道をあげても、ほとんど効果がない、ということは十分考えられます。逆に、JIT コンパイラでコンパイルする際に最適化処理がしやすいのは、AOT コンパイラが頑張って複雑化させたバイトコードより、ソースコードに忠実なシンプルなバイトコードではないでしょうか。AOT コンパイラが近視眼的に局所的な行った最適化が、実行時に得られる情報からプログラム全体を最適化するのを妨げてしまう、ということは十分に考えられます。

ということで、AOT コンパイラは余計なことをしないでシンプルに、意味のある高速化は VM にお任せ、という設計思想に基づいたアーキテクチャでは、Java 言語のコンパイル時点ではほとんど最適化をしない、ということになるのではないでしょうか。

◎質問者からの返答

AOTコンパイラの最適化によって出力されるコードを複雑化させない方が、JITを行いやすいというのは理解できました。

しかし、質問のプログラムの場合、事前に最適化を行ったほうがコードが単純になるパターンです。

この場合、余計な代入を取り除く最適化を行ったとしても、JITの妨げにはならないと思います。


また、JITが無い環境向けに、きっちり最適化を行うコンパイラはないのですかねえ。


4 ● t_shiono
●25ポイント

明確な情報源があるわけではないですが、1つ仮説のようなものは考えうると思います。

古い資料になってしまいますが、以下のサイトの「4.Javaの性質」の部分を見てみてください。

http://www.shudo.net/article/JavaWorld-200009-optimization/

・コードの書き方と性能の関係が安定していない。 どう書けば速くなるのかを予測しにくい。

・さまざまな実行方法があり、同じコードの性能が変わる。 実行方法やJVM、JITの種類に応じて、最適化の指針が異なる。

つまり、同じバイトコードであっても、その性能については、動作する環境によって変化することになります。

ここからは完全な推測ですが、

プログラムの動作から見れば、

0:iconst_0
1:istore_1
2:iconst_3
3:istore_1

に該当する箇所を省略することにより、最適化されるかと思われます。

ただ、上記のことから余計な処理をして、問題が起きるよりも、そのままバイトコードに落とし込んで、最適化は実行時にJVMに任せるというスタンスなのかなという気がします。

これまた少々古いですが、以下のページの「今月の質問: 実行時最適化は静的最適化に勝るか?」という部分を読んでもらえれば分かりますが、Javaの売りの1つは実行時最適化だという認識なのかと思います。

http://www.javanews.jp/javap/newsletter042.html


こういった背景のもとで、基本的には、Javaコンパイラは静的最適化はあまりしないと思われます。

これは、-0オプションが、「static、final および private なメソッドをインライン化することによって、コンパイルされるコードを最適化します。クラスはサイズが大きくなる可能性があることに注意してください。」ということからも想像できるかと思います。

参考:

http://ja.wikipedia.org/wiki/Java%E3%82%B3%E3%83%B3%E3%83%91%E3%...


想像の部分が多いですが、何かの参考になれば。

◎質問者からの返答

javacはJITされること前提のコードを生成することを理解しました。

しかし、この程度の最適化はやっておいた方が、むしろJIT自体も行いやすいとは思うんですが…


JITが無い環境も未だ有るので、ある程度の事前最適化を行うコンパイラもあっても良い気がします。

javac以外のjavaコンパイラの最適化について調査してみようと思います。

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ