末永 恭正 @YaSuenag
#ccc_r25
おことわり
 この資料は2014/05/17時点の
JDK8u/jdk8u-dev/hotspot(changeset
382a82b0a3e7:jdk8u20-b14)の内容を
基に記載しています。
OracleとJavaは、Oracle Corporation及びその子会社、関連会社の米国及びその他の国における登録商標です。
文中の社名、商品名等は各社の商標または登録商標である場合があります。
自己紹介
 末永 恭正(すえなが やすまさ) @YaSuenag
 某SIerでJavaやってるサンデープログラマー
 OpenJDK Author(jdk9)
 IcedTea Committer
 HeapStats作ってます
http://icedtea.classpath.org/wiki/HeapStats/jp
Metaspace
 Permanent世代の代わりに導入されたメタ
データ管理の仕組み
 JEP 122: Remove the Permanent Generation
http://openjdk.java.net/jeps/122
“HotRockit”の一環
Perm世代をネイティブ
メモリに追い出す
扱うデータ
 JVM実装でMetaspaceObjクラスを継承して
いるものがMetaspaceで扱われる
 ClassType
○ 純粋なクラス情報
 NonClassType
○ ClassType以外の情報
○ シンボル情報やメソッドの最適化に必要な情報など
MetaspaceObjの一覧
Metaspaceの種類
StandardMetaspaceType 通常のMetaspace
BootMetaspaceType ブートストラップクラスローダ
専用
ROMetaspaceType クラス情報ダンプ時に使用され
るMetaspace
(-XX:+DumpSharedSpaces)
ReadWriteMetaspaceType
AnonymousMetaspaceType 匿名クラス専用
(InvokeDynamic)
ReflectionMetaspaceType defineClass専用
(リフレクションなどの動的定義クラス)
ClassLoaderとVirtualSpace
Class
Loader
仮想メモリ空間VirtualSpaceList
VirtualSpace
VirtualSpace
:
VirtualSpace
VirtualSpace
:
Class
Loader
メタデータ用の
バラバラの空間を
仮想的に1つに
=Metaspace
VirtualSpace
Compressed
ClassSpace !?
CompressedClassSpace
 圧縮Oopが利用可能な状況でのみ使用できる、
クラス情報に特化したメモリ空間
 UseCompressedOopsが有効であることが必須
○ 最大Javaヒープサイズが32GB以下であること
 UseCompressedClassPointersでコントロー
ル可能
圧縮Oop?
 LP64向けHotSpotでのみ利用可能なメモリ使
用量削減の仕組み
 64bitポインタを、ベースアドレスからのオフ
セットを用いてムリヤリ32bitで表現
どういうこと?
 LP64のメモリアライメントは8byte
 ObjectAlignmentInBytesでコントロール
○ デフォルト:8
 つまり、下位3bitはゼロで埋められている
 3bit右シフトしても情報欠損が起きない!
 JavaヒープやCompressedClassSpaceは連続
空間
 そこの上にアロケートされるメモリは、すべて開始
アドレスからのオフセットで表現可能!
プログラム的に表すと…
http://www.oracle.com/technetwork/jp/articles/java/compressedoops-427542-ja.html
圧縮Oop(narrowOop)は符号なし32bitで表現されるので
uint_max(4GB)<< 3 = 4GB×23 = 32GB
圧縮できる上限
Metaspaceの成長
= VirtualSpaceListの成長
=VirtualSpaceの追加
 成長度合い
 チャンクサイズで決まります
Metaspaceとチャンクサイズ
チャンクサイズはイジれません
…
HotSpotの1ワード:LP64なら8バイト、それ以外なら4バイト
対数(log)です
ここまでのまとめ
 Metaspaceは1クラスローダにつき1つ割り当
てられる
 Metaspaceは連続したメモリ空間ではない
 Metaspaceで扱われる情報は大きく2種類
 クラス情報
 それ以外
 Metaspaceには6つの種類が存在する
 LP64環境でJavaヒープサイズが32GB以下の
場合はCompressedClassSpaceが作られる
Metaspaceでも
OutOfMemoryErrorは起きます!
実証コード
import java.nio.file.*;
import java.util.jar.*;
public class MetaFlood{
public static void main(String[] args) throws Exception{
Path rtjar_path = FileSystems.getDefault().getPath(
System.getProperty("java.home"), "lib", "rt.jar");
try(JarFile rtjar = new JarFile(rtjar_path.toFile())){
rtjar.stream().filter(e -> !e.isDirectory())
.map(e -> e.getName())
.filter(n -> n.endsWith(".class"))
.map(n -> n.substring(0, n.length() - 6).replace('/', '.'))
.forEach(n -> { System.out.println(n);
try{
ClassLoader.getSystemClassLoader().loadClass(n);
}
catch(ClassNotFoundException ex){}
catch(OutOfMemoryError oome){
System.out.println(oome.toString());
throw oome;
}
});
}
}
}
OOMEを起こしてみる
$ /usr/local/jdk1.8.0_05/bin/java -XX:CompressedClassSpaceSize=1m MetaFlood
:
java.lang.OutOfMemoryError: Compressed class space
Exception in thread "main“
:
$ /usr/local/jdk1.8.0_05/bin/java -XX:-UseCompressedClassPointers 
-XX:MaxMetaspaceSize=5m MetaFlood
:
java.lang.OutOfMemoryError: Metaspace
Exception in thread "main“
:
その1:CompressedClassSpace溢れ
その2:Metaspace溢れ
Permanentとの違い
 MetaspaceがGCされることはありません
 クラスローダが破棄されると、関連する
Metaspaceが削除されます
 FullGC後にMetaspace容量の調整を行います
 拡張 or 削減
 ここでは閾値の変更のみを行い、実際のメモリ伸
縮は行いません
MetaspaceGC
Metaspace起因のGCが起こるま
で
1. Metaspaceからメモリを取ろうとする
i. 今あるメモリから取ろうとする
ii. Metaspaceを拡張して取ろうとする
2. GCを起こす
i. 使われていないクラスローダをGCで回収し、
できるだけ空きMetaspaceを増やす
ii. Metaspaceを拡張して取ろうとする
~通常はここまででMetaspaceがとれる~
→OutOfMemoryError
GCログの例
[Full GC (Metadata GC Threshold)
[PSYoungGen: 496K->0K(2560K)]
[ParOldGen: 388K->836K(6656K)] 884K->836K(9216K),
[Metaspace: 7292K->7292K(9216K)], 0.0123187 secs]
[Times: user=0.02 sys=0.00, real=0.01 secs]
[Full GC (Last ditch collection)
[PSYoungGen: 0K->0K(2560K)]
[ParOldGen: 836K->792K(6656K)] 836K->792K(9216K),
[Metaspace: 7292K->7292K(9216K)], 0.0134180 secs]
[Times: user=0.04 sys=0.00, real=0.02 secs]
※見やすく改行しています
Metaspaceが
足りなくて
GCが発生
GCしても
まだ足りないため
最後の悪あがき
「最後の悪あがき」とは?
 ソフト参照も回収対象にし、できる限りクラス
ローダを回収しようとします
5つの手段
1. ツール
 jstat
 jcmd
 jconsole
 VisualVM
2. JMX
3. GCログ
4. NMT
5. HeapStats
jstat
 -gcなどが使えます(単位は全部KB)
 MC:Metaspace Capacity
 MU:Metaspace Used
 CCSC: Compressed Class Space Capacity
 CCSU: Compressed Class Space Used
 -gcmetacapacityというオプションもあります
 メタスペースサイズとGC回数・時間の取得用
$ /usr/local/jdk1.8.0_05/bin/jstat -gc 7831
… MC MU CCSC CCSU …
… 4864.0 2377.7 512.0 258.0 …
jcmd
 PerfCounter.printで細かく見れます
 sun.gc.metaspace
 sun.gc.compressedclassspace
$ /usr/local/jdk1.8.0_05/bin/jcmd 7831 PerfCounter.print
:
sun.gc.compressedclassspace.capacity=524288
sun.gc.compressedclassspace.maxCapacity=1073741824
sun.gc.compressedclassspace.minCapacity=0
sun.gc.compressedclassspace.used=264208
:
sun.gc.metaspace.capacity=4980736
sun.gc.metaspace.maxCapacity=1082130432
sun.gc.metaspace.minCapacity=0
sun.gc.metaspace.used=2434808
:
jconsole
 各メモリプールから確認できます
VisualVM
 Metaspace全体の確認ができます
JMX
 各メモリプールがあります
GCログ
 PermだったところがMetaspaceに変わって
います
$ /usr/local/jdk1.8.0_05/bin/java -XX:+PrintGCDetails SystemGC
:
[Full GC (System.gc())
[PSYoungGen: 368K->0K(1024K)]
[ParOldGen: 8K->251K(59904K)]
376K->251K(60928K),
[Metaspace: 2377K->2377K(1056768K)], 0.0047055 secs]
[Times: user=0.01 sys=0.00, real=0.00 secs]
:
※見やすく改行しています
Native Memory Tracking (NMT)
 細かい情報を簡単に知りたいときに最適
 -XX:NativeMemoryTracking=[summary|detail]
 取り方は2種類
 -XX:+UnlockDiagnosticVMOptions と
-XX:+PrintNMTStatistics でjava終了時に取得
 jcmd <PID> VM.native_memoryで外側から取得
 Metaspaceは”Class”の部分です
jcmd VM.native_memory
$ /usr/local/jdk1.8.0_05/bin/jcmd 8858 VM.native_memory
8858:
Native Memory Tracking:
Total: reserved=2330153KB, committed=135365KB
:
- Class (reserved=1062006KB, committed=10102KB)
(classes #374)
(malloc=5238KB, #153)
(mmap: reserved=1056768KB, committed=4864KB)
:
インスタンス
クラス数
HeapStats
 1.1系を使ってください
 閾値監視(SNMP Trap送信)もできます
ココ
注意
 Metaspaceの値はCompressedClassSpaceの
値も含む、全体的な値です。
 CompressedClassSpace⊆Metaspace
 NonClassTypeなMetaspaceを見たい場合は、
MetaspaceからCompressedClassSpace分を
引いてください。
Metaspace関連オプション(-
XX)オプション 意味 デフォルト
MinMetaspaceExpansion Metaspaceの最小拡張単
位
256KB
MinMetaspaceFreeRatio GC後の最小フリー量の
パーセンテージ
40
MaxMetaspaceFreeRatio GC後の最大フリー量の
パーセンテージ
70
MaxMetaspaceExpansion Metaspaceの最大拡張単
位
4MB
Metaspace関連オプション(-
XX)オプション 意味 デフォルト
UseLargePagesInMetaspace Metaspaceにラージペー
ジを使うか?
(UseLargePages必須)
false
TraceMetadataHumongousAllocation 大きなオブジェクトを
Metaspaceにアロケート
するのをトレースする
false
InitialBootClassLoaderMetaspaceSize ブートクラスローダ用
Metaspaceの初期値
LP64:4MB
それ以外:
2200KB
MetaspaceSize Metaspaceをリサイズさ
せるための閾値
環境依存
MaxMetaspaceSize 最大Metaspaceサイズ unsigned long
最大値
CompressedClassSpaceSize CompressedClassSpace
のサイズ
1GB
-XX:MetaspaceSizeでは
Metaspaceの初期サイズを
指定できません!
hotspot-gc-devに質問してみた
http://mail.openjdk.java.net/pipermail/hotspot-gc-dev/2014-April/009853.html
JIRAにも登録しました:
JDK-8039867: Incorrect description: -XX:MetaspaceSize
https://bugs.openjdk.java.net/browse/JDK-8039867
オプションをつける前に…
 Metaspaceは連続空間ではない
 1クラスローダ1メタスペース
 ブートストラップ以外のクラスローダの初期サイズは
変更できない
○ InitialBootClassLoaderMetaspaceSize(デフォルト4MB)
 CompressedClassSpaceはクラス情報「だけ」
 シンボルやメソッドプロファイル情報などは別領域
 長時間動作させていれば、Metaspace使用量はあ
る程度安定してくる(はず)
 動的ロードをガンガン行う場合はワカラナイ…
一番注意すべきオプション
CompressedClassSpaceSize
JDK7u55:
VmSize: 2153520 kB
JDK8u5:
VmSize: 3390320 kB
約1GBの差!
オプションを何もつけずに起動したときの仮想
メモリ使用量(VSZ)
なぜ1GBも差が?
 AMD64なJDK7ではMaxPermSizeの初期値が
64MB(jdk7u-devのHotSpotの場合)
 Perm目的で64MBしかリザーブしない
○ MaxPermSizeはプラットフォームやHotSpot VMの種
類によりデフォルト値が異なります
 CompressedClassSpaceのデフォルトは1GB
 1GBリザーブしてしまう!!
デフォルトのまま使うときは
オーバーコミットに注意しましょう!
MaxMetaspaceSize
青天井!
OSに殺されるかも…
古の情報
http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/diff/740e263c80c6/src/share/vm/runtime/arguments.cpp#l1.83
 昔は1クラス情報=1KBとみなしていました
 CompressedClassSpaceをデフォルトで100MBに
 昔はClassMetaspaceSizeというオプションでした
 100,000クラスはロードできるよ!という話
1クラスあたりの占有サイズ
 フィールド数、メソッド数によって異なります
 一概に「だいたいxxバイト」と表現できません
実測一番!
と、いうわけで…
-XX:MaxMetaspaceSize=そこそこ
-XX:CompressedClassSpaceSize=100m
※責任はもちません
-XX:MaxMetaspaceSize=そこそこ
①-Xmx32g以下の場合
②-Xmx32g超えの場合
③もう何も気にしたくない場合
-XX:-UseCompressedClassPointers
Metaspace

Metaspace