プロジェクト

全般

プロフィール

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総合

mark-sweep collector

CMS

G1GC


1年以上前に更新