Я много говорил о JVM раньше, и сегодня я собираюсь дополнить части, которые не были подробно освещены ранее, такие как: постоянная генерация и метапространство.
постоянное поколение
В памяти Java есть часть, называемая областью методов.До JDK8 методом реализации в виртуальной машине Hotspot была постоянная генерация (Permanent Generation), которая недоступна в других JVM.
В прошлом (когда пользовательские загрузчики классов обычно не использовались) классы были почти «статическими» и редко выгружались и повторно использовались, поэтому классы также можно было считать «постоянными». Кроме того, поскольку классы являются частью реализации JVM, они не создаются программой, поскольку они также считаются памятью «вне кучи».
Постоянная генерация — это непрерывное пространство памяти, которое мы можем установить перед запуском JVM.-XX:MaxPermSize
Значение постоянного поколения определяет размер постоянного поколения.Размер постоянного поколения по умолчанию составляет 64M для 32-битных машин и 85M для 64-битных машин.
Сборка мусора постоянного поколения и сборка мусора старого поколения связаны, как только одна из областей будет заполнена, обе области будут удалены. Но есть очевидная проблема, так как мы можем пройти‑XX:MaxPermSize
Установите размер постоянной генерации.Как только метаданные класса превысят установленный размер, программе не хватит памяти и произойдет ошибка переполнения памяти (java.lang.OutOfMemoryError: PermGen space).
Почему метаданные класса занимают так много памяти? Поскольку в виртуальной машине HotSpot до JDK7 строки, включенные в пул строковых констант, хранились в постоянном поколении, что вызывало ряд проблем с производительностью и ошибки переполнения памяти.
Чтобы решить эти проблемы с производительностью и сделать так, чтобы Hotspot можно было управлять как любой другой виртуальной машиной,元空间
производится.
метапространство
Metaspace — это новое дополнение к JDK8 от Hotspot, его суть аналогична постоянной генерации и является реализацией области методов в спецификации JVM. Но самая большая разница между метапространством и постоянной генерацией заключается в следующем:
Метапространство не находится в виртуальной машине, но используется
本地内存
. Поэтому по умолчанию размер метапространства ограничен только локальной памятью, но размер метапространства можно задать следующими параметрами:-XX:размер метапространства
>Исходный размер пространства, достижение этого значения вызовет сборку мусора для выгрузки типа, а сборщик мусора скорректирует значение: если освобождается большое количество места, это значение должно быть соответствующим образом уменьшено; если освобождается небольшое количество места, то при превышает MaxMetaspaceSize, увеличьте это значение соответствующим образом.
-XX:MaxMetaspaceSize
>Максимальное пространство, по умолчанию не ограничено.
В дополнение к двум указанным выше параметрам, определяющим размер, есть два свойства, связанные с сборщиком мусора:
-XX:MinMetaspaceFreeRatio
> После GC минимальный процент оставшейся емкости метапространства, уменьшающий сборку мусора, вызванную выделением пространства
-XX:MaxMetaspaceFreeRatio
> После GC максимальный процент оставшейся емкости метапространства, уменьшающий сбор мусора, вызванный освобождением места
Убрать эффект постоянной генерации
Поскольку метаданные класса размещаются в локальной памяти, максимальное выделяемое пространство пространства метаданных — это доступное пространство памяти системы. Таким образом, мы не получаем ошибок нехватки памяти, когда существует постоянное поколение, или таких вещей, как утечка данных, перемещаемых в подкачку. Конечный пользователь может установить максимальное свободное пространство для метапространства, если оно не установлено, JVM будет автоматически динамически увеличивать емкость метапространства в соответствии с размером метаданных класса.
Примечание. Удаление постоянного поколения не означает, что проблема утечки пользовательского загрузчика классов решена. Следовательно, вы также должны следить за своим потреблением памяти, потому что в случае утечки она займет много вашей локальной памяти, а также может привести к тому, что область подкачки будет подкачиваться еще хуже.
Управление памятью метапространства
Управление памятью метапространства осуществляется виртуальной машиной метапространства.
Раньше нам нужен был другой сборщик мусора для метаданных класса, теперь нам нужно просто выполнить C++ код виртуальной машины метапространства. В метапространстве жизненный цикл класса и его метаданных такой же, как и у соответствующего загрузчика классов. Другими словами, пока жив загрузчик классов, метаданные загруженного класса тоже живы, поэтому они не будут переработаны.
Если быть точным, область хранения каждого загрузчика классов называется метапространством, а все метапространства вместе — это метапространство, о котором мы говорили. Когда загрузчик классов помечен сборщиком мусора как уже не работающий, его соответствующее метапространство освобождается. В процессе рекультивации метапространства отсутствуют такие операции, как перемещение и сжатие. Но метаданные в метапространстве сканируются на наличие ссылок на Java.
Как именно он управляется?
Виртуальная машина метапространства отвечает за выделение метапространства, которое принимает форму выделения фрагментов. Размер фрагмента зависит от типа загрузчика классов. В виртуальной машине метапространства есть глобальный список свободных чанков.
- Когда загрузчику класса нужны фрагменты, он получает и поддерживает свой собственный список фрагментов из этого глобального списка фрагментов.
- Когда загрузчик классов больше не работает, содержащиеся в нем фрагменты будут освобождены и возвращены в глобальный список фрагментов.
- Фрагменты, хранящиеся в загрузчике классов, делятся на несколько фрагментов, каждый из которых хранит единицу метаинформации. Блоки в чанках распределяются линейно (распределение столкновений указателей). Куски выделяются из отображаемых в памяти областей. Эти глобальные области сопоставления виртуальной памяти связаны в связанный список, и после очистки области сопоставления виртуальной памяти эта часть памяти будет возвращена операционной системе.
постоянный пул времени выполнения
Пул констант времени выполнения является частью области методов в JDK6 и более ранних версиях JVM, а реализация области методов в виртуальной машине HotSpot — это постоянное поколение (Permanent Generation). Таким образом, постоянный пул времени выполнения также находится в постоянном поколении.
Однако JDK7 и более поздние версии JVM переместили пул строковых констант из области методов и открыли область в куче для хранения пула констант времени выполнения.
String.intern()
является нативным методом, его функция такова: если пул констант времени выполнения уже содержит строку, равную содержимому этого объекта String, вернуть ссылку на строку в пуле констант; если нет, создать строку с этой строкой в константе pool Строка с тем же содержимым и возвращает ссылку на строку, созданную в пуле констант.
существующие проблемы
Как упоминалось ранее, виртуальная машина метапространства принимает форму выделения фрагментов, а размер фрагмента определяется типом загрузчика классов. Информация о классе не имеет фиксированного размера, поэтому возможно, что выделенные свободные блоки и блоки, требуемые классом, имеют разные размеры, что может привести к фрагментации. Виртуальные машины Metaspace в настоящее время не поддерживают операции сжатия, поэтому фрагментация в настоящее время является самой большой проблемой.
Суммировать
Прежняя постоянная генерация оптимизирована в метапространство, потому что генерировать OOM легко, но даже при этом есть проблемы, не знаю, как JDK будет оптимизироваться в будущем?
Если вам интересно, вы можете посетить мой блог или обратить внимание на мой официальный аккаунт и номер заголовка, возможно, будут неожиданные сюрпризы.