プログラミング
ガベージコレクタの前にコードをチューニングする
Tune Code Before Your Garbage Collector (blog.vanillajava.blog)
要約
Javaにおけるメモリ割り当ての最適化は、ガベージコレクタの選択よりもはるかに大きな違いを生む可能性があり、最適なGCの選択さえも変えることがあります。特に高レイテンシが求められるシステムでは、冗長なログ出力の削減がGCの選択よりもp99.99レイテンシに劇的な影響を与えることがベンチマークで示されました。
全文翻訳
なぜガベージコレクタの前にコードをチューニングすべきなのか
Javaでメモリ割り当てを最適化することは、ガベージコレクタの選択よりもはるかに大きな違いを生む可能性があり、最適なガベージコレクタさえも変えるかもしれません。この投稿では、JLBHを使用してChronicle-FIXをテストし、50K/sで30分間実行される単純なイベントからレスポンスまでのレイテンシベンチマークに焦点を当てます。目標は、冗長な作業(この場合はSLF4Jを使用した各メッセージのログ出力)を行うシステムと、ログ出力しないシステム(Chronicle-FIXはChronicle Queueを使用して各メッセージを内部的に記録する)を比較し、これがガベージコレクタの選択をどのように変えるかを見ることです。
p99(最悪の100分の1)では、ガベージコレクタの選択はログ出力の最適化と同等の違いを生みます。しかし、p99.99(最悪の10,000分の1)では、ログ出力の最適化はガベージコレクタの選択よりも桁違いに重要になります。
最適化されていないベンチマーク
これは最適化されたベンチマークに、送信されるメッセージだけの1行のSLF4Jログを追加したものです。1行のログはたいしたことないように聞こえるかもしれませんが、すべてのメッセージでこれを実行すると、特にコードの残りの部分が低レイテンシ用に書かれている場合、大きな違いを生みます。
表1. slf4jロギングありのRTTレイテンシ分布
GCオプション p99 p99.99
Parallel large Eden, no large pages 16.86 20,480
ZGC, no large pages 12.21 19,694
G1 + COH, no large pages 12.02 20,349
G1, 2 MiB large pages 13.94 20,021
Shenandoah generational, no large pages 12.30 19,235
注: p99.99は数千マイクロ秒、つまり19〜20ミリ秒です。p99.99、つまり10,000回のうち最悪の1回はまれに聞こえるかもしれませんが、50K/sでは1秒あたり5回、1分あたり300回に相当します。
これらの結果に基づくと、Shenandoahが良い選択肢であり、Parallel GCを避けるべきだと結論付けるかもしれません。
ディスクIOはどれだけ違いを生むか
IOはしばしば遅延の重要な割合を占めます。そして、ログの書き込み場所を移動するだけで、その違いを見ることができます。この場合、/dev/shm(tmpfsファイルシステム)に移動します。
表2. /dev/shmへのslf4jロギングありのRTTレイテンシ分布
GCオプション p99 p99.99
Parallel large Eden, no large pages 34.50 10,994
ZGC, no large pages 10.86 9,617
G1 + COH, no large pages 10.90 10,043
G1, 2 MiB large pages 10.64 11,682
Shenandoah generational, no large pages 10.32 9,552
注: p99.99は数千マイクロ秒、つまり9〜10ミリ秒です。
Parallel GCのp99は外れ値かもしれませんが、それでもShenandoahを好むかもしれません。しかし、ログの書き込み場所を移動するだけで、はるかに大きな違いがあります。
冗長なロギングを削除する
Chronicle-FIXはすでにChronicle-FIXを使用して各メッセージを記録しているため、slf4jログは冗長です。低レイテンシコーディングでは、記録のためにChronicle-Queueを使用し、ログはほとんど使用しません。なぜなら、そうでなければそれが遅延の最大の原因となる可能性があるからです。ポリシーとして、起動後は情報レベルのログは出力しません。つまり、エラー/警告でありデフォルトでオンになっているか、デバッグログでありデフォルトでオフになっているかのどちらかです。本当に必要かどうかを決定してください。
表3. Chronicle-Queue記録のみのRTTレイテンシ分布
GCオプション p99 p99.99
Parallel large Eden, no large pages 7.14 8.94
ZGC, no large pages 7.82 9.36
G1 + COH, no large pages 8.30 12.4
G1, 2 MiB large pages 8.59 154.4
Shenandoah generational, no large pages 7.83 233.7
予想通り、p99は約2マイクロ秒低下しましたが、重要なのはp99.99が3桁低下したことです。また、ワークロードの変化により、好ましいガベージコレクタが反転しました。これら全てが1行のログ出力のためです。この場合、Parallel GCが最良に見え、Shenandoahはp99.99で最悪でした。
注: p99.99はマイクロ秒、つまり/dev/shmへのロギングよりも1000倍以上高速です。
結論
最適なガベージコレクタの選択とそのチューニング方法は、ワークロードに依存します。ワークロードが最初に最適化されていることを確認することが理にかなっています。なぜなら、a)場合によってはより大きな違いを生む可能性があり、b)選択肢さえも変える可能性があるからです。
ベンチマーク
パフォーマンス
Facebook X Pinterest Email 他のアプリ
コメント
コメントを投稿する
複数のAIに同じコードを最適化させる
2025年7月16日
異なるAIは実装方法が異なるため、同じ答えを提供せず、一貫して互いを上回るわけでもありません。最良のアプローチは、複数のAIを使用し、最も気に入ったものを選ぶことです。ここでの私の目標は、1つの例に基づいて勝者を宣言することではなく、異なるAIで得られる回答の多様性を示すことです。私は各AIに、このコードをより最適に実装する方法を提案するように依頼しました。
private static String formatOffset(int millis) {
String sign = millis < 0 ? "-" : "+";
int saveSecs = Math.abs(millis) / 1000;
int hours = saveSecs / 3600;
int mins = ((saveSecs / 60) % 60);
int secs = (saveSecs % 60);
if (secs == 0) {
if (mins == 0) {
return sign + twoDigitString(hours);
}
return sign + twoDigitString(hours) + twoDigitString(mins);
}
return sign + twoDigitString(hours) + twoDigitString(mins) + twoDigitString(secs);
}
private static String twoDigitString(int value) {
...続きを読む
Javaオブジェクトサイズの解明:コンパクトヘッダー、圧縮されたOops、そしてその先へ
2024年12月10日
はじめに
Javaでオブジェクトのサイズを測定することは、簡単ではありません。プラットフォームは、生のメモリ使用量よりも参照や抽象化を考慮することを推奨しています。それでも、オブジェクトがメモリにどのように収まるかを理解することは、特に高性能、低レイテンシのシステムで大きなメリットをもたらす可能性があります。長年にわたり、JVMは圧縮された普通オブジェクトポインタ(Compressed Oops)や、より最近ではコンパクトオブジェクトヘッダーのような最適化を導入してきました。これらのそれぞれが、オブジェクトのサイズがどれだけ大きくまたは小さく見えるかに影響を与える可能性があります。これらの要因を理解することは、メモリ使用量についてより具体的に推論するのに役立ちます。
オブジェクトサイズの測定
原則として、インスタンスを作成し、JVMの空きメモリの変化を観察することで、オブジェクトのサイズを推定できます。ただし、一貫した結果を得るためには、特定の要因を無効にする必要があります。例えば、TLAB割り当て(-XX:-UseTLAB)をオフにすると、メモリ使用量がより直接的に観測可能になります。繰り返し測定と中央値の計算は、不確…続きを読む
更新された略歴
2025年8月10日
Peter Lawreyは、超低レイテンシJavaシステムでの業績と、オープンソースのOpenHFTライブラリを主導したことで最もよく知られるオーストラリア/英国のソフトウェアエンジニア兼起業家です。彼は、ロンドンを拠点とするChronicle Softwareの創設者兼最高経営責任者であり、その技術は取引および市場インフラストラクチャのワークロードで使用されています。Lawreyは、Javaコミュニティの著名な人物でもあります。2015年にJava Championに選ばれ、カンファレンス主催者からは、Stack OverflowでJavaおよびJVMタグに関する最も多くの回答を提供した人物として紹介されており、長年続くVanilla Javaブログを執筆しています。(Chronicle Software、javachampions.org、qconnewyork.com、blog.vanillajava.blog)
キャリア
Lawreyは、イベント駆動型取引および市場データプラットフォーム向けのテクノロジーを構築するChronicle Softwareを設立し、率いています。同社は、そのソフトウェアが複数のティアワン銀行のシステムを支えていると述べています。2024年のプレスリリースでも、Chronicleが「t…続きを読む