[英]Java8 metaspace & heap usage
我有這個代碼動態生成類並加載它
import javassist.CannotCompileException;
import javassist.ClassPool;
public class PermGenLeak {
private static final String PACKAGE_NAME = "com.jigarjoshi.permgenleak.";
public static void main(String[] args) throws CannotCompileException, InterruptedException {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
ClassPool pool = ClassPool.getDefault();
pool.makeClass(PACKAGE_NAME + i).toClass();
Thread.sleep(3);
}
}
}
我針對Java 7(jdk1.7.0_60)啟動了這個類,正如預期的那樣,它填滿了PermGenSpace並且堆仍未使用 圖像顯示permgen使用超時,最后JVM終止
現在相同的代碼針對Java 8(jdk1.8.0_40-ea)運行並且正如預期的那樣它繼續擴展本機內存(Metaspace)但令人驚訝的是,1g的Metaspace它在OldGen中消耗了3g的堆(隨着時間的推移,幾乎是Metaspace的3倍)
該圖顯示了Metaspace使用超時和系統內存使用示例
這封來自Jon Masamitsu的電子郵件和這張JEP門票說
interned
String
和Class stats以及一些misc數據已移至Heap
當它將更多類加載到Metaspace中時,究竟是什么導致了堆的增加?
運行jmap -histo PID
以查看哪些對象占用堆空間。
當我運行你的例子時,我看到堆滿了Javassist輔助對象:
num #instances #bytes class name
----------------------------------------------
1: 592309 312739152 [Ljavassist.bytecode.ConstInfo;
2: 6515673 208501536 java.util.HashMap$Node
3: 2964403 169188824 [C
4: 1777622 102165184 [Ljava.lang.Object;
5: 4146200 99508800 javassist.bytecode.Utf8Info
6: 3553889 85293336 java.util.ArrayList
7: 2964371 71144904 java.lang.String
8: 593075 56944008 java.lang.Class
9: 592332 47388032 [Ljava.util.HashMap$Node;
10: 592309 37907776 javassist.bytecode.ClassFile
11: 592308 37907712 javassist.CtNewClass
12: 1185118 28555808 [B
13: 592342 28432416 java.util.HashMap
14: 1184624 28430976 javassist.bytecode.ClassInfo
15: 592309 28430832 [[Ljavassist.bytecode.ConstInfo;
16: 592322 23692880 javassist.bytecode.MethodInfo
17: 592315 23692600 javassist.bytecode.CodeAttribute
18: 592434 18957888 java.util.Hashtable$Entry
19: 592309 18953888 javassist.bytecode.ConstPool
20: 592308 18953856 java.lang.ref.WeakReference
21: 592318 14215632 javassist.bytecode.MethodrefInfo
22: 592318 14215632 javassist.bytecode.NameAndTypeInfo
23: 592315 14215560 javassist.bytecode.ExceptionTable
24: 592309 14215416 javassist.bytecode.LongVector
25: 592309 14215416 javassist.bytecode.SourceFileAttribute
26: 592507 9487584 [I
27: 8 6292528 [Ljava.util.Hashtable$Entry;
28: 212 18656 java.lang.reflect.Method
29: 407 13024 java.util.concurrent.ConcurrentHashMap$Node
30: 124 8928 java.lang.reflect.Field
當它將更多類加載到Metaspace中時,究竟是什么導致了堆的增加?
我的假設是,這是由你的例子創建的“普通”垃圾。 我猜測:
javaassist
代碼創建常規堆對象。 它們大多是“大”的,並且會導致它們直接分配到OldGen堆中。 或者其他原因造成的。
( 更新 - 看看@ apangin的答案,我現在懷疑他們是從YoungGen堆中開始的,並且終身......)
當在引擎蓋下調用classLoader.defineClass
,它會從包含類文件的字節數組中創建元空間中的對象。
OldGen的使用仍然存在......因為還沒有任何東西觸發完整的GC。
如果你調整了你的例子以便類可以訪問,然后強制一個完整的GC,我希望(希望)看到OldHeap使用率下降,表明它是“普通”垃圾而不是存儲泄漏。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.