为什么堆内存与Java 8中的元空间一起上升?

时间:2018-05-18 15:08:30

标签: java java-8 metaspace

我正在做一些测试,以了解元空间内存(Java 8以后)的工作原理。 当我动态创建100,000个类时,元空间内存正在增长(显然),但堆内存也在​​增长。 有人可以向我解释为什么会这样吗?

PS:我用128 MB的堆和128 MB的元空间运行测试。

FirestoreRecyclerAdapter

见下图:

enter image description here

enter image description here

2 个答案:

答案 0 :(得分:3)

您的类池使用堆内存。它有哈希表和列表等等。它还使用了使用堆内存的java反射代码。非gc'ed的堆内存可能是类池中的所有数据结构,一对哈希表,链表,数组列表,池等...例如,您创建的每个类都存储在类的哈希表中池。这是一个100,000元素的哈希表。

其次,如果您正在创建的类中有任何静态初始值设定项,那么将使用堆内存。静态初始化器包括静态字段初始化和静态块代码。

答案 1 :(得分:1)

我对您的代码进行了专门研究ClassPool#makeClass。我注意到有几点导致堆空间随着元空间的增加而增加。

  1. 它由{s}在哈希表
  2. 中的方法makeClass创建的类cache
      

    受保护的Hashtable类;

    因此,对于百万分之十的课程,它有每个课程的条目。因此,堆空间也增加了,并且它不是GC,因为你的for循环仍然使用哈希表引用并且不断更新因此不符合gc。

    1. CtNewClass创建类的新实例,它具有如下构造函数定义:

        CtNewClass(String name, ClassPool cp, boolean isInterface, CtClass superclass) {
          super(name, cp);
          this.wasChanged = true;
          String superName;
          if (!isInterface && superclass != null) {
              superName = superclass.getName();
          } else {
              superName = null;
          }
      
          this.classfile = new ClassFile(isInterface, name, superName);
          if (isInterface && superclass != null) {
              this.classfile.setInterfaces(new String[]{superclass.getName()});
          }
      
          this.setModifiers(Modifier.setPublic(this.getModifiers()));
          this.hasConstructor = isInterface;
      }
      
    2. 在上面的代码行this.classfile = new ClassFile(isInterface, name, superName);实际上为每个类创建了新的ConstPool实例,即每个实例的新HashMap实例,以及这些实例在堆空间上保留内存。

        

      HashMap类; //来自ConstPool类

           

      HashMap字符串; //来自ConstPool类

      此外,这会创建两个新的ArrayLists。观察上面构造函数中的this.fields = new ArrayList();this.methods = new ArrayList();语句。此外,还有一个新的链接列表this.attributes = new LinkedList();

      因此,结论是ClassPool的缓存管理占用了大量的堆空间。然后每个类都有自己的集合集来管理属性,常量等。

      希望它有所帮助!