Почему куча памяти растет вместе с metaspace в Java 8? - PullRequest
0 голосов
/ 18 мая 2018

Я провожу небольшой тест, чтобы понять, как работает метапространственная память (Java 8 и выше).Когда я создаю 100 000 классов динамически, память метаскопа растет (очевидно), но память кучи также растет.Может кто-нибудь объяснить мне, почему это происходит?

PS: я провожу тест со 128 МБ кучи и 128 МБ метапространства.

@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");
}

См. Изображения ниже:

enter image description here

enter image description here

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

Я изучил ваш код, особенно ClassPool#makeClass.Я заметил несколько моментов, которые приводят к увеличению пространства кучи по мере увеличения метапространства.

  1. Это 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 имеет управление кэшем, которое занимает достаточно места в куче.Тогда у каждого класса есть свой набор коллекций для управления свойствами, константами и т. Д.

Надеюсь, это поможет!

0 голосов
/ 18 мая 2018

Ваш пул классов использует кучи памяти.У него есть хэш-таблицы, списки и другие вещи.Он также использует код отражения Java, который использует кучи памяти.Куча памяти, которая не является gc'ed, это, вероятно, все эти структуры данных в пуле классов, пара хеш-таблиц, связанные списки, списки массивов, пулы и т. Д. Например, каждый создаваемый вами класс хранится в хеш-таблице класса.бассейн.Это хэш-таблица на 100 000 элементов.

Во-вторых, если в создаваемых вами классах есть статические инициализаторы, которые будут использовать кучу памяти.Статические инициализаторы включают в себя инициализации статического поля и код статического блока.

...