簡體   English   中英

Java8元空間和堆使用

[英]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並且堆仍未使用 Java 7內存使用情況 圖像顯示permgen使用超時,最后JVM終止

現在相同的代碼針對Java 8(jdk1.8.0_40-ea)運行並且正如預期的那樣它繼續擴展本機內存(Metaspace)但令人驚訝的是,1g的Metaspace它在OldGen中消耗了3g的堆(隨着時間的推移,幾乎是Metaspace的3倍)

Java8內存使用情況 該圖顯示了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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM