Tuning Java SE for Throughput and Latency

今日の午後「Tuning Java SE for Throughput and Latency」というタイトルでセミナーをやらせていただきました。

元々は昨年出版された「Java Performance」という本を書かれた Charlie Hunt さんのセミナーです。内容的には Java Performance 本のサブセットのような感じで、それに少し最近の動向等も加えました。

Java Performance 本は Safari Online で入手して、斜め読みしましたが良い本です。HotSpot VM に特化していますが、VM の動作原理(Theory of Operation) 的な章では HotSpot VM の様々なサブシステムの概要が良く説明されています。HotSpot JVM の動作に興味がある方には、いきなり膨大なソースを読むより役立つでしょう。また、GC は種類やオプションも多く、デフォルトより踏み込んでチューニングしていくにはそれなりの基礎知識が必要ですが、それらもいろいろな観点で説明されています。また、後半では App Server など Java EE 環境でのパフォーマンスのアプローチも説明されています。トータルで 680 ページ程度、なかなかのボリュームです。

質問も多くいただいたのですが、きれいに答えが出ない物もありました。

HotSpot ではない VM を使っていて、おそらくネイティブメモリがリークしてそうだが、なかなか絞れないという事も聞きました。ネイティブメモリのリークとなると、良いツールが無いと、ネイティブのメモリ確保に繋がるような呼び出しのスタックトレースを集めて傾向をみると言ったような泥臭い方法しか最終的には無かったりします。再現方法が確実であればいろいろ試行錯誤も出来るのですが。古い OS であれば brk/sbrk system call を呼ぶスタックトレースを集めていくと傾向が見えたりします。最近の glibc はリニアに伸びる事しか出来ない brk の不便さを克服する為か、malloc でもほとんど mmap で領域を確保しているので、mmap にいたるトレースも調べる必要がありそうです。Valgrind とかツールもあるのですが、本番環境でしか減少が見られず、低負荷で情報収集というのは難しい面があります。glibc malloc 自身の fragmentation も起きる時は起きるので、気になります。気軽に jemalloc などと切り替えられるとよいのですが。

また、Java code のアロケーションパターンには余り変化がなさそうなのに、徐々にマイナーGCの所要時間がふえるという現象の話も聞きました。それが Full GC をするとマイナーGC時間は短くなると。そして、とある java program 側の変更でそれが解消されたそうです。マイナーGCの時間の内訳が分からないと難しい所です。大半の GC/Heap がコピーコレクタを使っているので、コピーの量が一定であれば他に要因がありそうです。Remembered Set/Write Barrier の話もしたのですが、Old から Young の参照がだんだん増えるようであれば、時間が徐々にかかる様になる原因かも知れません。ある程度のプロモーションはマイナーGC毎に起きているという事でしたので、可能性としてはあります。検証するには debug build でいいオプションがあればそれをつかって、無い場合には独自の instrumentation を加えて検証するというちょっと手間のかかる事になりそうです。

元のセミナーの中で、Performance test を積極的に、リアクティブなケースでも、プロアクティブなケースでも、デザインの段階から作成して、自動テストのサイクルに組み込むと色々役に立つという事を Charlie Hunt さんが提案されていました。それなりに手間はかかるのですが、うまく作り込めれば予想外のパフォーマンスに関する副作用を速く検知できたり、パフォーマンチューニングや、パフォーマンストラブルシュートで非常に役立つでしょう。このような取り組みの具体的な成果が出て来たら、是非聞いてみたい物です。

本の中でも出てきますが、プロファイルツールとして Solaris Studio Performance Analyzer という物があります。その中の collect -j on に続けて java program コマンドラインを指定するとサンプリングベースで cpu, lock, stack trace などを収集してくれます。これを analyzer で表示すると、実行時にどのスレッドがいつ何をしていたかが java stack, native stack で分かりますし、コンパイルされたコードの中身やインタープリタのどの辺とかも分かります。このスレッドの時系列の表示もカラフルできれい。Java のスレッドも VMThread, compiler thread, GC thread 等の様子も分かり、頭の中の理解が具体的に GUI で確認できて、これはとても面白いツールでした。Solaris, Linux で動きます。いろいろなプログラムのプロファイルとってみたいと考えてます。

ともあれ、終わってホッとしています。