JVMのメモリとGCを復習する

JavaVMのメモリとGCを復習する。

メモリ構造と設定オプション

ヒープ
 Javaヒープ: 最大:-Xmx, 初期:-Xms
  New: サイズ:-Xmn, NewとOldの割合:-XX:NewRatio
   Eden
   Survivor: SurvivorとEdenの割合:-XX:SurvivorRatio
  Old
 Permヒープ: 最大:-XX:MaxPermSize, 初期:-XX:PermSize
 Cヒープ
スレッドスタック: 1スタックの最大:-Xss

※全て非標準オプションおよびHotSpot VM Specific Options
Javaヒープ:newで確保される領域
※Permヒープ:クラス等のメタデータが格納される領域
※Cヒープ:JavaVM自身のリソースが格納される領域。スレッドのスタックなど

GC

JavaVMによる、使用済みメモリ領域(主にJavaヒープ)の回収・空き領域の確保。
大まかな流れ:Eden=CopyGC⇒Survivor=…⇒Old
(Edenが一杯になるとCopy GCによりSurvivorへ。この際、Eden内・Survivor内の参照なしオブジェクトは廃棄される。これを繰り返して、Survivorにずっと残り続けたオブジェクトはOldへ。Oldが一杯になったらFull GC

対象領域

Copy GC: New領域のみ
Full GC: Javaヒープ全体とPermヒープ
(※Permヒープの枯渇でも Full GC が発生する)

性能影響
  • GC の処理中はアプリケーションの実行は停止される
  • Full GC は、対象領域が大きいため処理時間が長い

各領域のサイジングで Copy GC 発生をコントロールし、 Full GC の発生を抑制する。

OutOfMemoryError

主に、Javaヒープが不足している場合に投げられる。
Javaヒープ不足である場合は、スタックトレースに「java.lang.OutOfMemoryError: Java heap space」と出力され、JavaVMの実行は継続する。
Cヒープ不足の場合は、スタックトレースの先頭が Native Method である。

なお、OutOfMEmoryErrorが表示されてJavaVMが強制終了された場合は、Cヒープ不足である。

状況把握

GCログから状況を把握する。
JavaVM起動オプション -verbose:gc 指定で表示する。
非標準オプション -Xloggc:file を使えば、GCログをファイル出力する。
詳細情報も見たい場合は、下記オプションを追加。

  • -XX:-PrintGCDetails
  • -XX:-PrintGCTimeStamps

もちろん、VisualVMでも見ることができる。

実験

テストコード
public class Test {
	public static void main(String[] args) {
		int roopCount = 1000000;
		int toOldTiming = 10; // 何ループ毎にOld領域まで生かすオブジェクトとするか
		String[] old = new String[roopCount/toOldTiming];

		for(int i = 0; i < 1000000; i++){
			String test = "test"+i;
			if(i % toOldTiming == 0) {
				old[i/toOldTiming] = test;
			}
		}
	}
}
テストコマンド
javac Test.java
java -Xmx2m -Xloggc:gc.log -XX:-PrintGCDetails Test