JRockit JVMのガベージコレクションのまとめ
JRockit JVM の ガベージコレクションの仕組みを、公式のドキュメント読んでざっくりまとめてみました。
改めて調べてみると、HotSpot JVM とほとんど変わらないみたいです。既にご存知の方には釈迦に説法ですが、JVM のメモリ管理について初学者の方は、参考にしてみてください。
JRockit JVM が使用するメモリ領域
スタック領域や、パーマネント領域といった分け方もありますが、参照先では以下のような分け方で説明されています。
- ヒープメモリ
- 二世代のガベージコレクションが利用される場合、「ナーサリ(若い領域)」と「古い領域」の2つの領域(世代)に分割される *1
- ナーサリ(若い領域)
- 新しいオブジェクトの割り当てのために予約されている領域
- 古い領域
- 若いコレクションで昇格されたオブジェクトや、大規模オブジェクトが割り当てられる領域
- ヒープメモリ以外のメモリ領域
若いコレクションと、古いコレクション
二世代のガベージコレクションを利用する場合、ガベージコレクションには、「若いコレクション」と「古いコレクション」とがあります。
- 若いコレクション
- ナーサリに保持された古いオブジェクトを、古い領域に「昇格(移動)」する処理
- 古いコレクション(後述)や一世代のガベージコレクション(ナーサリのないヒープに対するガベージコレクション)よりも、格段に速くメモリ領域を開放できる
- ナーサリの「保持領域」
- ナーサリの一部に確保される領域
- ここに保管されたオブジェクトは、直後の若いコレクションで昇格されない。このことにより、オブジェクトが割り当てられた直後に昇格してしまうのを防止する
- 古いコレクション
- 古い領域のガベージコレクション
- 実際にメモリを開放する処理
小規模オブジェクトと大規模オブジェクト
JRockit JVM では、オブジェクト割り当て時に小規模オブジェクトと大規模オブジェクトが区別されます。
小模オブジェクトと大規模オブジェクト
- 通常 2 ~ 128 KB が区別の基準となる
- 小規模か大規模化は、おおよそ以下の項目により決定される
- JVMのバージョン
- ヒープサイズ
- ガベージコレクション
- プラットフォーム
小規模オブジェクト
- スレッドローカル領域(TLA)に割り当てられる
- 二世代のガベージコレクションの場合、TLA はナーサリから確保される
- 大規模オブジェクト
- TLA に収まらないオブジェクト
- 二世代のガベージコレクションの場合、古い領域に割り当てられる
- 大規模オブジェクトの割り当てには、複数の Java スレッド間の、オブジェクトキャッシュの同期を頻繁に行う必要がある *2
ガベージコレクション
二世代のガベージコレクションを利用している場合、ここでの記述内容は、古いコレクションに該当します。 マーク アンド スイープ モデルという、ガベージコレクションのアルゴリズムについての説明です。
- マーク アンド スイープ モデル
- JRockit JVM のガベージコレクションモデル
- マークフェーズとスイープフェーズからなる
- マークフェーズの動作
- 現在使用されているオブジェクトを識別し、マークを付ける
- 以下のようなオブジェクトが生存状態としてマークされる
- Java スレッド、ネイティブ ハンドルおよびその他のルートソースから到達可能なオブジェクト
- 上記のオブジェクトから到達可能なオブジェクト
- スイープフェーズの動作
- マークフェーズとスイープフェーズの組み合わせ方により、いくつかの方式がある
- モーストリ コンカレント マーク アンド スイープ モデル(コンカレント ガベージコレクション)
*4
- ガベージコレクション処理の大部分で、Java スレッドが実行され続ける。同期のために数回停止する必要はある
- パラレル マーク アンド スイープ モデル(パラレル ガベージコレクション)
- システム内の利用可能な CPU すべてを使用して、可能な限り高速でガベージコレクションを行う
- ガベージコレクション処理の間、すべての Java パレットは休止する
- モーストリ コンカレント マーク アンド スイープ モデル(コンカレント ガベージコレクション)
*4
モースト コンカレント マーク アンド スイープ における処理の詳細
モースト コンカレント マーク アンド スイープ では、マーク処理とスイープ処理において、それぞれ4つのフェーズが順に実行されます。
モーストリ コンカレント マークの4つのフェーズ
名前 | 動作 | Java スレッドの停止 |
---|---|---|
初期マーキング | 生存しているオブジェクトのルートセットを識別する | あり |
コンカレント マーキング | ルートセットからの参照にしたがって、生存している残りのオブジェクトを検索してマークする | なし |
プレクリーニング | コンカレント マーキング中のヒープの変更を識別し、生存しているオブジェクトを検索してマークする | なし |
最終マーキング | プレクリーニング中のヒープの変更を識別し、生存しているオブジェクトを検索してマークする | あり |
モーストリ コンカレント スイープ の4つのフェーズ
名前 | 動作 | Java スレッドの停止 |
---|---|---|
スイープ(1回目) | ヒープの半分をスイープする。この間、オブジェクトは残り半分のヒープ領域に割り当てられる | なし |
休止(1回目) | 残り半分に切り替えるための休止 | N/A |
スイープ(2回目) | 残り半分のヒープをスイープする。この間、オブジェクトは残り半分のヒープ領域に割り当てられる | なし |
休止(2回目) | 同期、および統計の記録のための休止 | N/A |
世代別ガベージコレクション(若いコレクション)
二世代のガベージコレクションを利用している場合、ヒープメモリ上にナーサリが存在します。ナーサリの保持領域外のオブジェクトを古い領域に昇格するのが、若いコレクションです。
若いコレクションの間、Java スレッドは停止します。