为什么在Java8中堆内存和元空间一起上升?

为什么在Java8中堆内存和元空间一起上升?,java,java-8,metaspace,Java,Java 8,Metaspace,我正在做一个小测试来了解元空间内存(Java8以后的版本)是如何工作的。 当我动态创建100000个类时,元空间内存在增长(显然),而堆内存也在增长。 有人能解释一下为什么会发生这种情况吗 PS:我用128MB的堆和128MB的元空间运行测试 @Test public void metaspaceTest() throws CannotCompileException, InterruptedException { ClassPool cp = ClassPool.getDefault();

我正在做一个小测试来了解元空间内存(Java8以后的版本)是如何工作的。 当我动态创建100000个类时,元空间内存在增长(显然),而堆内存也在增长。 有人能解释一下为什么会发生这种情况吗

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

@Test
public void metaspaceTest() throws CannotCompileException, InterruptedException {

ClassPool cp = ClassPool.getDefault();
System.out.println("started");

for (int i = 0; i <= 100000; i++) {
    Class c = cp.makeClass("br.com.test.GeneratedClass" + i).toClass();
    Thread.sleep(1);
    if (i % 10000 == 0) {
    System.out.println(i);
    }
}

System.out.println("finished");
}
@测试
public void metaspaceTest()抛出CannotCompileException、InterruptedException{
ClassPool cp=ClassPool.getDefault();
System.out.println(“已启动”);

对于(int i=0;i您的类池使用堆内存。它有哈希表、列表和其他东西。它还使用使用堆内存的java反射代码。未gc’ed的堆内存可能是类池中的所有数据结构,一对哈希表、链接列表、数组列表、池等。例如,您创建的每个类由类池存储在哈希表中。这是一个100000元素的哈希表


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

我对您的代码进行了研究,尤其是
类池#makeClass
。我注意到有几点导致堆空间增加随着元空间的增加

  • cache
    方法makeClass在哈希表中创建的类
  • 受保护的哈希表类

    因此,对于1千万个类中的每一个类,它都有相应的条目。因此,堆空间也会增加,并且它不是GC,因为哈希表引用仍然被for循环使用,并且不断更新,因此不符合GC的条件

  • 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;
    }
    
  • 在第行上方的代码中
    this.classfile=new classfile(isInterface,name,superName);
    实际上为每个类创建新的ConstPool实例,即为每个实例创建新的HashMap实例,这些实例在堆空间上保留内存

    HashMap类;//来自ConstPool类

    HashMap字符串;//来自ConstPool类

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

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

    希望有帮助