2011年2月23日水曜日

やっぱりJavaはここが遅い!

このエントリーをはてなブックマークに追加
Pocket

基本的にJavaは『遅い』と思われている。理由は二点あって、一つは過去のバージョンのJavaの実行速度が遅かった歴史的な点であり、一つは実際に依然として遅い面がある点だ。しかし、漠然と遅いと思われている事が多い。

数値演算などでは、JavaはC言語に迫る速度を出す事もある。The Computer Language Benchmarks Gameでは逆転している項目もある。しかし、Javaアプリケーションの体感速度はC++アプリケーションを上回ることは無いとされる。

これはJITコンパイラによる初期動作の遅さ、ガーベッジ・コレクション(GC)の駆動などの複合的な要因で発生する『遅さ』なのだが、単純なベンチマークだと特徴を掴みづらい。そこで変則的なベンチマークを作って、このJavaの『遅さ』を簡単に計測してみた。

1. ベンチマーク方法

コッホ曲線の描画時間を連続して測るベンチマークを作成した。ソースコードはMercurialのリポジトリで公開をする。

JITによる最適化が何巡目で発揮されるかが分かるように、1巡目から20巡目まで、それぞれのコッホ曲線の描画時間を計測する。また、System.gc()を呼んだ後に、0.1秒のウェイトを入れることで、描画中のGCを抑えるコードを加えている。さらに、アプリケーション自体の起動時間は除外している。さらに、デフォルトではアプリケーションはコンソールにベンチマーク結果を表示するが、引数でファイル名を指定して、そのオーバーヘッドを抑えている。

なお、ベンチマークはGC発生時・GC抑制時で、それぞれ5回づつ行った。また、Java 1.6.0_22を-serverオプションでHotSpotを有効にし、メモリ関係のオプションを-Xms6m -Xmx64mとして、GCが発生する状態でベンチマークを取っている。ただし、HotSpotの有無は、今回のベンチマークでは余り速度に関係が無いようであった。

2. 立ち上がりが遅い

GCを抑制した状態でベンチマークを取ると、1巡目から4巡目まで描画時間が劇的に減少する。4巡目以降は収束し、大きな変動は無い。1巡目は0.027秒、4巡目は0.007秒と4倍程度実行速度は高速化されており、立ち上がりが遅い特性が良く表れている。

Javaは動的にクラスをロードするため、1巡目は特に不利になる。2巡目以降はJITが働くためか、徐々に速度が上がっていく。JITプロファイラのアルゴリズムのためか、最初から完全に最適化はされないようだ。なお、コッホ曲線の描画ルーチンは再帰的な構造を持つため、CPUのキャッシュには1巡目の途中で乗っていると考えられる。

3. GCが遅い

GCを抑制し無い状態でベンチマークを取ると、全般的に速度が遅く、また描画時間のばらつきが大きくなる。4巡目で描画時間は収束しているように思えるが、その後の誤差も大きい。

誤差の理由は明確で、コッホ曲線の描画時間ルーチンではオブジェクトの生成が頻繁に行われているため、Java VMは積極的にGCを行っているようだ。

上はGC抑制時の描画時間の平均値と、GC発生時の平均値を比較したものだが、GC発生時の方があらゆる巡目で、GC抑制時よりも描画時間がかかっている。20巡目までの平均値で、GC無しの方が約2倍と高速になっている。

4. GCが遅いからと言って、Javaが駄目なわけではない

今回のベンチマークで計測したGCは、アプリケーション全体を止めるフルGCではなく、バックグラウンドで動くコンカレントGCであるため、あまり気になるものでは無かった。

また、スクリプト言語のようにプログラマがメモリ管理を行わない言語は、JavaのGCと同じ問題を抱える事になる。Objective-CでGCを用いた場合も同様だ。最近はGCが無い言語は流行らないので、GCがあるからJavaは致命的に遅いとは言えない。

5. Javaの立ち上がりとGCの遅さは気にしないのが良い

わざわざ計測してみたが、Javaのコーディングをする上で、立ち上がりとGCの遅さは考えない方が良い。GCに関しては、使い捨てオブジェクトを抑制することで速度の改善が期待できるが、立ち上がりの遅さに関しては成す術が無い。

近年の計算機の速度を考えると、必ずしもCやC++に速度的に迫る必要は無く、上記二つのJavaの特性は、あまり気にせず受け入れてしまう方が良いと思う。

6. まとめ

Objective-Cの『遅さ』を計測したら、JavaやC++の5倍も遅かった』でObjective-Cの弱点を評価していたもので、今回はJavaの弱点を評価してみた。どちらも有用なツールなので、長所と短所をよく理解した上で使いこなす事が理想だ。

JVMの挙動に関しては、上述のように独特な動きがあるので、動作速度がクリティカルなアプリケーションの場合は良く注意したい。ただし、人気の開発環境であるNetBeansやEclipseに限らず、FreeMindのようなアプリケーションも軽快に動いており、よほどの規模でないと問題になる事は少ないであろう。

最後にJavaのHotSpot VMに関して、『Javaパフォーマンス計測 文字列操作編』に興味深い測定結果があったので紹介しておきたい。不適切なオブジェクトを使ったコードの実行速度が、何万回もループを繰り返すうちに適切なコードに近い速度に変化したという記事で、JVMの特徴を良く現している。

0 コメント:

コメントを投稿