And*_*dre 13 java java-8 metaspace
我正在做一些测试,以了解元空间内存(Java 8以上)的工作原理.当我动态创建100,000个类时,元空间内存正在增长(显然),但堆内存也在增长.有人可以向我解释为什么会这样吗?
PS:我正在使用128 MB的堆和128 MB的元空间运行测试.
@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");
}
Run Code Online (Sandbox Code Playgroud)
见下图:
我特别研究了你的代码ClassPool#makeClass。我注意到有几点导致堆空间随着元空间的增加而增加。
cache通过哈希表中的 makeClass 方法创建的类受保护的哈希表类;
因此,对于十分之一的类,它具有每个类的条目。因此,堆空间也会增加,并且它不是 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;
}
Run Code Online (Sandbox Code Playgroud)在上面的代码中,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();。
因此,结论是 ClassPool 有其缓存管理,占用了大量的堆空间。然后每个类都有自己的一组集合来管理属性、常量等。
希望能帮助到你!