Я изучил ваш код, особенно ClassPool#makeClass
.Я заметил несколько моментов, которые приводят к увеличению пространства кучи по мере увеличения метапространства.
- Это
cache
классы, созданные методом makeClass внутри хеш-таблицы
защищенные классы Hashtable;
Итак, для десятого миллиона классов в нем есть запись для каждого из них.Следовательно, пространство кучи также увеличивается, и это не 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 strings;// из класса ConstPool
Кроме того, это создает два новых ArrayLists.Обратите внимание на операторы this.fields = new ArrayList();
и this.methods = new ArrayList();
в конструкторе выше.Кроме того, новый связанный список this.attributes = new LinkedList();
.
Следовательно, вывод заключается в том, что ClassPool имеет управление кэшем, которое занимает достаточно места в куче.Тогда у каждого класса есть свой набор коллекций для управления свойствами, константами и т. Д.
Надеюсь, это поможет!