Javaガベージコレクション¶
ガベージコレクションの搭載状況¶
JDKのバージョンと、JDKに搭載されるガベージコレクションの種類を下表に示します。
JDK 1.0 | JDK 1.1 | JDK 1.2 | JDK 1.3 | JDK 1.4 | JDK 5 | JDK 6 | JDK 7 | JDK 8 | JDK 9 | JDK 10 | JDK 11 | JDK 12 | JDK 13 | JDK 14 | JDK 15 | JDK 16 | JDK 17 | JDK 18 | JDK 19 | JDK 20 |
mark-sweep collector | ||||||||||||||||||||
Incremental GC | ||||||||||||||||||||
Serial GC | ||||||||||||||||||||
Parallel GC | ||||||||||||||||||||
Concurrent Mark Sweep GC | ||||||||||||||||||||
G1GC | ||||||||||||||||||||
ZGC | ||||||||||||||||||||
Shenandoah GC |
GCの種類¶
- mark-sweep collector
初期のJavaVM搭載GC。シングルスレッドで動作。部分的なコンパクションを実施(mark-sweep-compact collectorでもある) - Incremental GC
Trainアルゴリズムによる停止時間最小化を図るGC。 - Serial GC
世代別GC。シングルスレッドで動作。若い世代はcopying collector、古い世代はmark-sweep - Parallel GC
世代別GC。Stop the World(STW)を並列処理で動作。若い世代は並列copying collector、古い世代はmark-sweep
古い世代のSTWが並列処理になるのはJDK 5以降 - Concurrent Mark Sweep GC
世代別GC。若い世代は並列copying collector、古い世代はconcurrent collector - G1GC
世代別GC。ヒープを固定サイズの領域群に分割し、領域を若い世代(EdenとSurvivor)、古い世代に分類し、それぞれ並列copying collector - ZGC
非世代別、遅延最小化を目指すGC。コストのかかる処理をアプリケーションと並行し、stop-the-worldを極小化(10ms以下)する。 - Shenandoah GC
非世代別で領域分割GC。アプリケーションスレッドと並行してGCのマーク処理、退避処理、参照更新を行う。アプリケーションスレッドを一時停止するのは、初期マーク、最終マーク、初期参照更新、最終参照更新のわずかな時間に留める。
ガベージコレクションの選択¶
JavaVMは、複数のガベージコレクターが搭載されており、利用者がオプションで選択できるようになっています。
ガベージコレクションの種類¶
JDK 1.3以降、世代別ガベージコレクション(GC)が使われています。世代別GCは、若い世代のヒープ領域を対象とするマイナーGC、旧い世代のヒープ領域を対象とするフルGCで構成されます。世代別GCにもいくつかガベージコレクターの種類があります。
Java SE 8に搭載されているGCの種類¶
- シリアルコレクター
単一CPU(スレッド)でGC処理を実行する。マイナーGC/フルGCともに処理中はアプリケーションを停止させるStop-the-world(STW)あり。小さなヒープ(100MB以下)を対象とする。 - パラレルコレクター(スループット型)
複数CPU(スレッド)でGC処理を実行する。マイナーGC/フルGCともにSTWあり。単位時間あたりのGC処理効率を停止時間よりも優先する。 - Concurrent Mark Sweep(CMS)
可能な限りアプリケーションの動作と並行してGC処理を実行し、GC処理によるアプリケーション停止時間(STW)を極力少なくする。マイナーGCはSTWあり、フルGCは基本STWなし(markフェーズで短時間のSTWあり)、CMSが機能しなくなったとき(断片化の著しい進行、CPUリソース不足など)はシリアル型のフルGCを実施(コンパクションなど)。 - G1GC
領域分割し、領域毎に若い世代、旧い世代を設定する。可能な限りアプリケーションの動作と並行してGC処理を実行し、GC処理によるアプリケーション停止時間(STW)を極力少なくする。大きなヒープ(おおよそ4GB以上)を主な対象とする。フルGCもコピーコレクターを使用しコンパクションも行われる。
どれを選択するかはトレードオフの問題です。
- 出典:「Javaパフォーマンス」(オライリー刊 2015年)
Java SE 9以降のJDKへのGCの搭載状況¶
- ZGC
Experimentalな搭載は、Linux/x64版はJDK 11、Linux/AArch64版はJDK13、macOS版とWindows版(Windows 10 1803+、Windows Server 2019+)はJDK 14
Productionな搭載は、JDK 15
領域分割し、世代別管理はしない。カラーポインタでオブジェクトの状態(マーク済み、退避済み)を管理、退避リージョンにフォワーディングテーブルを設け退避したオブジェクトの参照を管理する。
- Shenandoah GC
Experimentalな搭載は、Linux/x64版はJDK 12の一部のディストリビューション
Productionな搭載は、JDK 15
領域分割し、世代別管理はしない。並列マークに加え、並列コンパクション(brooks pointer)を行う。
GCの種類補足¶
GC種類 | 若い世代のGC | 旧い世代のGC | |
---|---|---|---|
シリアルコレクター | STWなシリアルScavenger | STWなシリアルMark-Sweep-Compact | |
パラレルコレクター | STWなパラレルScavenger | STWなパラレルMark-Sweep-Compact | |
CMS | STWなパラレルScavenger1 | Concurrent Mark-Sweep | |
G1GC | Fully-young collection | Partially-young collection | |
ZGC | 世代別は採用せず | ||
Shenandoah GC | 世代別は採用せず |
1 パラレルコレクターの並行Scavengerとは違う、CMSと連携する"ParNew"。性能はやや遅い模様。
パラレルScavenger¶
- STWあり、複数のGCスレッド
CMS¶
- アプリケーションと並行して(Concurrent)GCの処理を行う。但し、GC処理の一部ではアプリケーションを停止させる
- マイナーGC: ここはParallel Scavenger(並列コピーGC)が使われる
- メジャーGCのうち、初期マーク処理とリマーク処理
G1GC¶
- ヒープを等サイズのリージョンに分割し、リージョン単位でGCを行う。
- GCの対象とするリージョンを選び、リージョン内の生存オブジェクトを別の空きリージョンへコピーした後、そのリージョンを初期化(空きリージョン)とする
- 並行マーキングと退避から構成
- 並行マーキングは、1.初期化マーク/2.並行マーク/3.最終マーク/4.生存オブジェクトカウント/5.後始末の5フェーズで、STWは1.と3.と5.
- 退避は、1.回収集合選択/2.ルート退避/3.退避の3つで、いずれもSTW
- マイナーGC(Fully-young collection)は、すべての若い世代リージョンを回収集合として選択
- メジャーGC(Partially-young collection)は、すべての若い世代リージョンと一部の旧い世代リージョンを回収集合として選択
- 若い世代リージョンには、生成リージョンと残存リージョンがある
ZGC¶
- リージョンベース(世代管理なし)
- 並行(Concurrent)GC
- 1.初期化マーク/2.並行マーク(リマーク)/3.最終マーク/4.並行コンパクション/5.フォワーディングテーブル作成の5フェーズで、STWは1.と3.
- 停止時間の極小化を目指したGCで、使用メモリ量が多くてもGC停止時間を増やさない
- 8MB~16TBのヒープサイズを扱う
- コンパクション
- 未使用メモリをOSへ返却
- オブジェクトの64bitヘッダーでカラーポインタ管理
Shenandoah GC¶
- リージョンベース(世代管理なし)
- 並行(Concurrent)GC
- 1.初期化マーク/2.並行マーク/3.最終マーク/4.並行クリーンアップ/5.並行退避/6.参照更新初期化/7.並行参照更新/8.最終参照更新/9.並行クリーンアップの9フェーズで、STWは1.と3.と6.と8.
- ブルックスポインタを導入し、停止(STW)せずに退避したオブジェクトの参照を可能に
デフォルトで使われるガベージコレクタ¶
Java SE 8¶
OS | JavaVM | リソース | ガベージコレクタ |
---|---|---|---|
Windows | 32bit | ー | シリアルコレクタ |
64bit | パラレルコレクタ | ||
Linux | 32bit | 1CPUまたは2GBメモリ未満 | シリアルコレクタ |
2CPU以上かつ2GBメモリ以上 | パラレルコレクタ | ||
64bit | ー | パラレルコレクタ |
CMSとG1GCを使うにはJavaVMオプションで明示的に指定します。
Java SE 9以降¶
計算機スペック | ガベージコレクタ |
---|---|
非サーバークラス | シリアルコレクタ |
サーバークラス | G1GC |
- サーバークラスは、CPUが2個以上かつヒープサイズが1792MB以上
どのガベージコレクションを選択するか¶
ZGC, ShenandoahがProductionとして搭載される以前¶
大雑把には次の指針になります。
- CPU(コア)が1つならシリアルGC
- CPU(コア)が複数あり、STWの平均時間を短くしたい、アプリケーション実行時のCPUリソースに余裕が少ない場合、パラレルGC
- アプリケーション実行時のCPUリソースに余裕があり、GCの処理量(オーバーヘッド)は増えてもSTWのワースト時間を最小限にしたい場合、CMSまたはG1GC
- ヒープサイズが大きい場合、G1GC
- 断片化が発生しやすい場合、G1GC
ガベージコレクションの指定¶
JavaVM起動時のオプションで選択したガベージコレクションの設定をします。
使用するガベージコレクタの指定¶
Java SE 8での指定です。
ガベージコレクタ種類 | JavaVM起動オプション |
---|---|
シリアルコレクター | -XX:+UseSerialGC |
パラレルコレクター | -XX:+UseParallelGC |
CMS | -XX:+UseConcMarkSweepGC |
G1GC | -XX:+UseG1GC |
GCが使用するCPU(スレッド)数¶
パラレル型GCの使用CPU数¶
次の値がパラレル型GC(パラレルコレクタ、G1コレクタ)で使用する並列数(CPU数)です。
通常は、実行するPCのCPU数(スレッディング型のCPUの場合はコア数ではなくスレッド数)です。
uintx ParallelGCThreads = 4 {product}
- 2コア4HTのIntel Coreプロセッサ上でのデフォルト値
ヒープメモリ¶
ヒープメモリのサイズ¶
デフォルトのサイズ¶
若い世代と古い世代の配分¶
若い世代の中のEdenとSurvivorの配分¶
ヒープメモリ上のオブジェクト¶
オブジェクト・ヘッダー¶
ヒープメモリ上に格納するオブジェクト(インスタンス)のメモリ構造は、先頭にオブジェクト・ヘッダーが置かれる。
- 非配列のオブジェクト
markワード | 32bit版なら4バイト、64bit版なら8バイト |
klassワード | 32bit版/圧縮OOP有効な64bit版なら4バイト、圧縮OOP無効な64bit版なら8バイト |
gap | 4バイト、配置ルールで必要なときに置かれる(いつ?) |
インスタンス・フィールド | クラスの定義次第 |
- 配列のオブジェクト
markワード | 32bit版なら4バイト、64bit版なら8バイト |
klassワード | 32bit版/圧縮OOP有効な64bit版なら4バイト、圧縮OOP無効な64bit版なら8バイト |
lengthワード | 4バイト |
gap | 4バイト、配置ルールで必要なときに置かれる(いつ?) |
インスタンス・フィールド |
- 圧縮OOPが有効なのは次のAND条件
- -Xmxが未指定、または-Xmxで指定したサイズが32GB未満
- -XX:-UseCompressedOopsをJavaVM起動オプションに指定していない
- gapは配置ルールで必要な場合
- 圧縮OOPが有効のときに32bitの管理ポインタと64bitポインタとの変換する方法
- ヒープサイズが4GB以下のときは直接アドレッシング(ヒープが仮想メモリ空間の0~4GBのアドレスに位置する)
- ヒープサイズが4GB超から32GBまでのときは、オブジェクトは8バイト境界に置かれる前提でポインタを圧縮
- ヒープサイズが32GB超のときはベースアドレスと8バイト境界の組み合わせが必要になるのでklassワードは64bitに戻る(?)
技術情報へのリンク¶
GC総合
- Javaガベージコレクションのエッセンス(InfoQ翻訳記事 Martin Thompson著)
- GC Tuning Confessions Of A Performance Engineer(JavaOne 2015 SF)
各GCの図解が秀逸 - Hotspot JVMの圧縮OOP
- JDKの超高速な新ガベージ・コレクタを理解する(Java Magazine 2019年11月)
ZGC、Shenandoah、G1GC改善 - A brief history of garbage collection
mark-sweep collector
CMS
- CMS GCおさらい(JJUG CCC 2014 Fall「Concurrent Mark-Sweep Garbage Collection再入門」フォローブログ)
- Java 7 CMS GCの基本的な情報の整理
G1GC
- 徹底解剖「G1GC」実装編(電子書籍 無償 中村成洋著)
- G1 GC おさらいと #jjug_ccc で発表した話(JJUG CCC 2015 Fall)
- Garbage-First Garbage Collector: Migration to, Expectations, and Advanced Tuning(JavaOne 2013 SF CON3754)
- Garbage-First Collector: Current and Future Adaptability and Ergonomics—Manual Tuning(JavaOne 2013 SF CON5497)
- HOL5429_Tuning_Low-Pause_Garbage_Collection.pdf (Garbage-First Collector Tuning(JavaOne 2013 SF HOL5429))