JVM GC の知識ポイント
JVM でよく使われるガベージコレクタには、主に Serial、Parallel、ParNew、CMS、G1、ZGC などがあります。各コレクタは 並行能力、停止時間、スループット、適用シナリオ がそれぞれ異なります。以下、代表的なガベージコレクタを整理して説明します。
Serial コレクタ
対応パラメータ:-XX:+UseSerialGC -XX:+UseSerialOldGC
Serial コレクタは JVM の中で最も基礎的で歴史の長いガベージコレクタであり、シングルスレッドでガベージコレクションを実行 します。ガベージコレクション実行時、JVM は STW(Stop The World) を発動します。つまりすべてのユーザースレッドを一時停止し、ガベージコレクションが完了してからビジネススレッドの実行を再開します。
アルゴリズムの実装面では、Serial コレクタは 新生代(Young 世代)でマーク・コピーアルゴリズム(Copying) を、老年代(Old 世代)でマーク・コンパクトアルゴリズム(Mark-Compact) を使用します。回収プロセス全体で GC スレッドが 1 本しかないため、実装はシンプルで安定していますが、ヒープメモリが大きい場合や CPU コア数が多い場合には、ガベージコレクションの効率が明らかに低下します。
そのため Serial コレクタは、メモリ規模が小さく、CPU コア数が少ないアプリケーション環境、例えば初期の Client モード JVM やリソース制約のあるシステムに向いています。
Parallel Scavenge コレクタ
対応パラメータ:-XX:+UseParallelGC -XX:+UseParallelOldGC
Parallel Scavenge コレクタは Serial コレクタの マルチスレッド版 であり、その核心的な目標は システムのスループット(Throughput)を高める ことです。ガベージコレクション時には複数の GC スレッドを並列に実行し、全体の回収効率を向上させます。
デフォルトでは GC スレッド数は CPU コア数とほぼ同じですが、パラメータ -XX:ParallelGCThreads でスレッド数を手動指定することもできます。Parallel コレクタのアルゴリズムは Serial コレクタとほぼ同じで、新生代ではマーク・コピーアルゴリズム、老年代ではマーク・コンパクトアルゴリズム を使用します。
Parallel コレクタは 停止時間よりもスループットを重視 するため、バックグラウンド計算型サービスやバッチ処理システム に非常に適しています。ヒープメモリ規模が中程度(例えば 3~4GB 前後)のアプリケーションシナリオでは、このコレクタで良好なパフォーマンスを得られます。
ParNew コレクタ
対応パラメータ:-XX:+UseParNewGC
ParNew コレクタは Serial コレクタのマルチスレッド版 と理解できますが、その主な用途は単独での使用ではなく、CMS コレクタと組み合わせて使う ことにあります。ParNew は 新生代のガベージコレクション を担当し、CMS は 老年代のガベージコレクション を担当します。
実装方式として、ParNew は マルチスレッド並列回収メカニズム を採用し、新生代では引き続き マーク・コピーアルゴリズム を使用します。CMS は低停止時間を目標とするコレクタであり、Serial コレクタはシングルスレッドであるため、実際に CMS を使う際は通常 ParNew を組み合わせて新生代の回収効率を高めます。
この組み合わせ(ParNew + CMS)は、初期の Web サービスや停止時間に敏感なシステムで多く使われていました。
CMS コレクタ
対応パラメータ:-XX:+UseConcMarkSweepGC
CMS(Concurrent Mark Sweep)コレクタは主に 老年代のガベージコレクション に使用され、その設計目標は ガベージコレクション時の停止時間を可能な限り減らす ことです。CMS の重要な特徴のひとつは、GC スレッドとユーザースレッドの並行実行を許可する ことで、アプリケーションの一時停止時間を削減できる点です。
CMS は マーク・スイープアルゴリズム(Mark-Sweep) を使用し、トリカラーマーキング(三色マーキング法) に基づいてオブジェクトの到達可能性分析を行います。回収プロセス全体は通常、次の 5 つのフェーズに分かれます:
- 初期マーク(Initial Mark) STW を発動し、GC Roots が直接参照するオブジェクトのみをマークします。オブジェクト数が少ないため実行は非常に高速です。
- 並行マーク(Concurrent Mark) ユーザースレッドと並行して実行し、オブジェクトグラフ全体を走査してすべての到達可能なオブジェクトをマークします。
- 再マーク(Remark) 再び STW を発動し、並行マーク中にオブジェクト参照の変化によって生じたずれを修正します。
- 並行スイープ(Concurrent Sweep) ユーザースレッドと並行して実行し、マークされなかったオブジェクトを掃除します。
- 並行リセット(Concurrent Reset) CMS の内部状態をリセットし、次回の GC に備えます。
CMS のフロー図:

CMS は回収プロセスを 1 つのステップから複数のステップに分割し、マークとスイープの両方を細分化したうえで、最も時間のかかるオブジェクトのマークステップをユーザースレッドとの並行実行に回しました。これによりアプリケーションは STW の停止をほとんど感知しなくなります。初期マークと再マークの 2 フェーズにごく短い STW があるだけで、それ以外のプロセスはすべて並行して進みます。こうして CMS は 最短の回収停止 という目標を達成しました。ただし停止時間が最短であることは、回収プロセス全体の所要時間が短いことを意味しません。実際には CMS の全体的な回収時間は他のガベージコレクタより長く、あくまで停止時間が最小であるにすぎません。
G1 コレクタ
対応パラメータ:-XX:+UseG1GC
G1(Garbage First)コレクタは JDK9 以降のデフォルトのガベージコレクタ であり、主に 大容量メモリのサーバー環境 で使用されます。新生代と老年代で物理的に区分けする従来のガベージコレクタと異なり、G1 はヒープ全体を複数の Region(領域) に分割します。
各 Region は必要に応じて動的に Eden、Survivor、Old 領域 として使用できます。G1 は各 Region 内のゴミの比率を統計し、ゴミが最も多く、回収の効果が最も高い Region を優先的に回収します。これが「Garbage First」という名前の由来です。
G1 のもうひとつの重要な特徴は 予測可能な停止時間モデル です。パラメータ -XX:MaxGCPauseMillis で期待する最大停止時間を設定でき、G1 はその目標に応じて回収戦略を自動調整します。
全体の回収フローは 初期マーク、並行マーク、最終マーク、Region 回収 などのフェーズを含みます。CMS と比べて、G1 はメモリフラグメンテーションの削減、大容量ヒープメモリのサポート、停止時間の制御においてより優れたパフォーマンスを発揮するため、現代の JVM 環境で広く使用されています。
ZGC コレクタ
ZGC は JDK11 で導入された低レイテンシガベージコレクタ で、その核心的な目標は ミリ秒レベルの GC 停止時間の実現 です。ほとんどの場合、ZGC の STW 停止時間は 10ms 以内 に抑えられ、TB クラスのヒープメモリでも安定を保てます。
ZGC の実装はいくつかのキー技術に依存しています。カラードポインタ(Colored Pointer)、ロードバリア(Load Barrier)、そして Region ベースの ZPage メモリ管理メカニズム です。これらの技術により、ZGC はほとんどの時間、ユーザースレッドと並行してガベージコレクションを実行できます。
ZGC の主な回収プロセスは 並行マーク、並行リロケーション、並行参照修正 を含みます。大部分の作業が並行フェーズで完了するため、アプリケーションスレッドへの影響は非常に小さくなります。
そのため ZGC は、超大容量メモリのサーバー、リアルタイムシステム、金融取引などレイテンシに極めて敏感なアプリケーションシナリオ に非常に適しています。
主要 GC コレクタの比較
- Serial:シングルスレッド回収、小規模アプリケーション向け
- Parallel:マルチスレッド回収、スループット優先
- ParNew + CMS:低停止時間の構成(JDK8 でよく見られる)
- G1:現代 JVM のデフォルトコレクタ、大容量メモリサービス向け
- ZGC:超低レイテンシガベージコレクタ、TB クラスのメモリシステム向け
| コレクタ | 種類 | スレッドモード | 主要アルゴリズム | 停止の特徴 | 適用シナリオ |
|---|---|---|---|---|---|
| Serial | 新生代 + 老年代 | シングルスレッド | コピー + マーク・コンパクト | STW 時間が長め | 小規模アプリ、シングルコア CPU |
| Parallel Scavenge | 新生代 | マルチスレッド | コピーアルゴリズム | スループット優先 | バックグラウンド計算、バッチ処理 |
| Parallel Old | 老年代 | マルチスレッド | マーク・コンパクト | スループット優先 | 高スループットサービス |
| ParNew | 新生代 | マルチスレッド | コピーアルゴリズム | 停止が短め | CMS との組み合わせ用 |
| CMS | 老年代 | 並行 | マーク・スイープ | 低停止 | Web サービス、低レイテンシシステム |
| G1 | 全ヒープ(Region) | 並行 + 並列 | コピー + マーク・コンパクト | 予測可能な停止 | 大容量メモリサーバー |
| ZGC | 全ヒープ(Region) | 高度な並行 | マーク + リロケーション | <10ms の停止 | 超大容量ヒープ、低レイテンシシステム |
発展:Golang GC の基本メカニズム
Go は バージョン 1.5 からトリカラーマーキング並行 GC(Tri-color Mark and Sweep)を導入 し、その後のバージョンで継続的に最適化を重ね、現在では成熟した 並行マーク + 並行スイープ + ライトバリア(Write Barrier) の GC 体系が形成されています。
Golang GC の核心的な特徴は以下のとおりです:
- トリカラーマーキングアルゴリズム(Tri-color Marking)
- 並行マーク(Concurrent Mark)
- ライトバリア(Write Barrier)によるオブジェクト参照の一貫性保証
- STW 時間が極めて短い(通常 < 1ms)
- GC の自動トリガー(ヒープ増加比率に基づく)
Golang GC の主なフローは以下のとおりです:
- STW Start:すべての Goroutine を一時停止し、GC Root を初期化します。
- 並行マーク(Concurrent Mark):GC がユーザー Goroutine と並行して実行され、トリカラーマーキングでオブジェクト参照を走査します。
- マーク終了(Mark Termination):短時間の STW で、すべてのオブジェクトのマーク完了を保証します。
- 並行スイープ(Concurrent Sweep):マークされなかったオブジェクトを回収し、プログラムと並行して実行されます。
JVM GC と Golang GC の核心的な違い
JVM は 複数のガベージコレクタ(Serial、CMS、G1、ZGC など)を採用し、世代別回収メカニズムをサポートしており、異なるアルゴリズムとパラメータの組み合わせによってさまざまなシナリオに適応 します。一方 Golang は設計当初から統一されたトリカラーマーキング並行 GC(Tri-color Mark & Sweep)体系を採用し、世代別回収を行わず、並行マーク、ライトバリア、極めて短い STW によって低レイテンシの回収を実現しています。そのため全体構造がよりシンプルで、チューニングコストも低くなっています。
なぜ Go は世代別 GC をしないのでしょうか?それは Go チームが、世代別 GC はレイテンシに敏感なシステムでは効果が明確でない一方、ランタイムの複雑さを増すと考えているからです。
まとめ
Serial から ZGC まで、JVM ガベージコレクタの進化の主軸は、実のところスループットと停止時間の間で絶えずトレードオフを図ることでした。シングルスレッドの Serial はシンプルさと安定性が持ち味で、Parallel はスループットを追求し、ParNew + CMS は並行実行によって低停止を実現し、G1 は Region 化によって停止を予測可能にし、ZGC はカラードポインタとロードバリアによって停止をミリ秒レベルまで抑え込みました。コレクタを選ぶ際は新しいものを追いかける必要はなく、鍵はやはりアプリケーションのヒープ規模とレイテンシ要件です。Golang の統一された非世代別 GC 設計と比較すると、2 つのランタイムが複雑さと柔軟性においてどう異なるトレードオフをしているかも、よりはっきり見えてきます。
COMMENTS