仕組み
メモリ領域
次のページが明快で詳しい
http://d.hatena.ne.jp/tanakakns/20120508/1336467306
jconsoleでの表示名称では
ヒープ Eden ┐ Survivor ┘2つあわせてNew領域 Tenured ─ Old領域
非ヒープ Code Cache Perm Gen [shared-rw] Perm Gen [shared-ro] Perm Gen
- SurvivorはFrom/Toの二つの同サイズのメモリ領域からなるが、jconsoleで表示しているサイズはそのうち1個分のようだ。
- 表示名称はjconsoleが決めているというよりは、監視対象のJVM内のMBeanが提供する名前をそのまま表示しているのかも。
- 3つに分かれているPerm Genがそれぞれ何なのかが不明。
New世代GC(ScavengeGC、マイナーGCともいう)
http://www.atmarkit.co.jp/fjava/rensai3/javavm02/javavm02_1.html
新規オブジェクトは、Edenからメモリを割り当て。
やがてEdenがいっぱいになり、いっぱいになるとNew世代GCが起動。
New世代GCはCopying方式
- Edenから使用中のオブジェクトのみ選んでSurvivorのToにコピー。
- Survivor内でも、Fromから使用中のオブジェクトをToにコピー。
- EdenとFromはクリア。
- ToとFromの役割(名前)を入れ替え。
以下の場合にSurvivorのToからTenured(Old領域)に移動する。
- コピーの回数が一定回数を超えたオブジェクト
- Toがあふれた場合?
ここでの「一定回数」は、1から-XX:MaxTenuringThreshold指定値の範囲で動的に決定される。
実行中、アプリの動作は停止。
jconsoleで観測すると、
- Edenは、0付近から100%付近までだんだん使用率があがり、0付近に戻る、というのを繰り返す。
- Survivorは、New世代GCが実行されたタイミングで変化。Edenから移ってくれば増えるし、Tenured(Old領域)に移動すれば減る。
Survivorとして表示されるサイズ(使用済み、確定、最大)は、From/Toに分割されたバッファ1つ分のサイズの模様。
Old世代GC(Full GCとも)
http://www.atmarkit.co.jp/fjava/rensai3/javavm02/javavm02_1.html
mark-sweep-compact方式
Old領域の中で、使用中のオブジェクトにマークを付け、未使用のものを削除し、空いた隙間を詰める。
実行中、アプリの動作は停止。
なお、コンカレントGCを使用した場合は挙動が異なり、停止時間が短くなる。
http://www.atmarkit.co.jp/fjava/rensai4/troublehacks02/troublehacks02_1.html
設定
サイズの指定
- -Xms, -Xmx
初期,最大ヒープサイズ
初期=最大とすると、ヒープの動的な拡大・縮小に伴う性能劣化を防ぐことができるらしい。
http://www.atmarkit.co.jp/fjava/rensai4/troublehacks02/troublehacks02_2.html
- -XX:NewSize~, -XX:MaxNewSize
初期,最大New領域の初期サイズ
- -XX:SurvivorRatio
EdenのサイズをSurvivor(To1個分)で割った値。なお、ToとFromは同じサイズが割り当てられる。
例えば、NewSizeが10mで、SurvivorRatioが8の場合、Eden:To:From=8:1:1 で分割されるので、Edenが8メガバイト、ToとFromがそれぞれ1メガバイトとなる。省略時は、試したVMでは8であった。OSやヒープ総量によって変わるのかも。
- -XX:PermSize, -XX:MaxPermSize
初期,最大Permanent領域サイズ
- -Xss
スレッドスタックサイズ
その他の設定
- -XX:TargetSurvivorRatio
Survivor領域がいっぱいだと判断される使用率
- XX:MaxTenuringThreshold
New領域内でコピーされる回数の閾値の最大値。上述のNew世代GCの説明を参照。
- XX:+DisableExplicitGC
System.gc()を無効化
System.gc()
- jconsoleで観察しているところでは、Survivorの内容が Tenured Genに移動し、Survivorが空になるようだ。Edenの分もTenured Genに移動しているかもしれない。そうだとすると、ある程度の時間を経れば未使用となるオブジェクトもTenuredに移動してしまうことになり、その点では、不利になる。
- Old世代GCも走る。
finalizer
finalizerを持つオブジェクトは1回目のGCでfinalizer実行対象だとマークされ解放はされず、finalize完了後のGCで解放されるとのこと。したがって、GCの頻度が低いと、不要なのに解放されずにたまる状況が発生するらしい。
http://www.atmarkit.co.jp/fjava/rensai4/troublehacks09/troublehacks09_3.html
メモ
- GCログを取得するオプション
-Xloggc:/path/to/file.log -XX:+PrintGCDetails
- jconsole
更新間隔をn秒にするには-interval=nを指定する。
http://docs.oracle.com/javase/jp/6/technotes/tools/share/jconsole.html
- リフレクションで自動生成されるクラスによりPerm領域を圧迫する事例
「強制FullGCを実行することでアンロードすることは可能」
http://d.hatena.ne.jp/Kazzz/20080208/p1