日本オラクル開催のセミナー「Tuning JavaSE for Throughput and Latency」を受講しました。
もともとはJavaOne Tokyo 2012のプログラムだったものが開催できず今日あらためて開催したとのことです。
スライドは、Charlie Hunt氏*1作成のもので、説明は日本オラクルのサポートエンジニアの方からでした。(講師の方のブログ発見)
内容はHunt氏が著した次の書籍に基づくものとのことです。
Java Performance (Java Series)
- 作者: Charlie Hunt,Binu John
- 出版社/メーカー: Prentice Hall
- 発売日: 2011/10/04
- メディア: ペーパーバック
- 購入: 1人 クリック: 49回
- この商品を含むブログを見る
さて、スライドが300枚弱とまずその量に圧倒されました。5時間枠で流すので、情報の洪水状態でした。一応JavaVM(HotSpot VM)のガベージコレクションについては過去調べており、また最近は仕事でパフォーマンスチューニングをしていた経験もあるのですが、それでも消化不良気味でした。
講義内容は到底ブログに収まるものではないので、気になったことをメモするに留めます。
メモ
-XX:+PrintFlagsFinal
オプションで指定できる項目の確定値を標準エラー出力に表示します。デフォルトの値を確認するときに便利です。
同一マシンで複数JavaVMを稼働
JavaVM(HotSpot VM)のエルゴノミクス(デフォルト)は、並行/並列GCスレッド数などを他にJavaVMが動いていない前提で決めるので、複数JavaVMを動かすときは明示的にオプションでスレッド数を減らすか、OSのパーティショニングが可能なら利用できるCPUを制限するなどの処置が必要です。
GC選択の方針
- まず、Parallel GCを使用する
- いろいろ改善を図っても停止時間等が要件を満たせないなら、CMSやG1GCへ変更する
- CMS、G1GCはマイナーGCの停止時間を減らせるが、スループットは低下する
- CMSを使うときはParallel GCのときより旧世代ヒープを大きく取る(1.2倍目安)
- CMSの場合、無理に新世代領域に留めず旧世代領域にインスタンスをプロモートさせ早めにFull GCをするのもよい
- JavaVM複数に分割するのも有効なチューニング方法
- G1GCは、JavaSE 7 u4から製品レベルのサポート
- TrainGCはなくなった
- 将来CMSはG1GCに置き換わるかも(今はG1GCが登場したばかりなので様子見)
- CMSとG1GCの違いは3つ:コンパクションを行いフラグメントをなくす、使うのが簡単(CMSが難しすぎ)、予測性(≠ハードリアルタイム)。G1GCはコピー型で、CMSはコンパクションがなければコピーしない。
- Incremental CMSというものがあるが、小さい構成向けでサーバーVMではまず使わない
新世代のエデンとサバイバースペース
今回のセミナーでは、サバイバースペースの大きさにまで言及していました。エデンとサバイバーの大きさについてはどう考えればよいか分からなかったので収穫でした。
ただし、そのチューニングは高度なトレードオフで一概には決められず、かなり深い話になります。
JavaVMの最適化
GCの最適化
- エデン、旧世代領域は、スレッド毎にTLAB(Thread Local Allocation Buffer)に分割され、ロックせずに領域を割り当てる。領域割り当てはエデンの場合10CPU命令程度のため高速。昔TLABは特定スレッドが過度に領域割り当てると他のTLABは空いているのにメモリ不足となるフラグメントが起きたが、今は自動調整でサイズを変えるので解消したとのこと。
- CMSはフリーリストでメモリ管理しているのでプロモートが遅い
- Initial Markはルートから直接たどれるもののみ処理(短い時間で済む)
- printgcstatsツール(オープンソース)
- ライブデータサイズ(ヒープ)を計測し、ヒープサイズはライブデータサイズの3-4倍を取る
- ライブデータサイズ(パーマネント)を計測し、パーマネントサイズはライブデータサイズの1.2-1.5倍を取る
- ライブデータサイズ(ヒープ)の1-1.5倍を新世代領域に、残りを旧世代領域にする
64bitVMでのメモリ効率
ヒープサイズが<26GBのとき、-XX:+UseCompressedOopsを指定すると、オブジェクトを指すポインタが32bitで済むのでメモリ効率がよくなります。