Как измерить фрагментацию в метапространстве Hotspot?

Я пытаюсь отладить ошибку OutOfMemoryError: Metaspace в своем приложении. Прямо перед OOME я вижу в журналах gc следующее:

{Heap before GC invocations=6104 (full 39):
 par new generation   total 943744K, used 0K [...)
  eden space 838912K,   0% used [...)
  from space 104832K,   0% used [...)
  to   space 104832K,   0% used [...)
 concurrent mark-sweep generation total 2097152K, used 624109K [...)
 Metaspace       used 352638K, capacity 487488K, committed 786432K, reserved 1775616K
  class space    used 36291K, capacity 40194K, committed 59988K, reserved 1048576K
2015-08-11T20:34:13.303+0000: 105892.129: [Full GC (Last ditch collection) 105892.129: [CMS: 624109K->623387K(2097152K), 3.4208207 secs] 624109K->623387K(3040896K), [Metaspace: 352638K->352638K(1775616K)], 3.4215100 secs] [Times: user=3.42 sys=0.00, real=3.42 secs] 
Heap after GC invocations=6105 (full 40):
 par new generation   total 943744K, used 0K [...)
  eden space 838912K,   0% used [...)
  from space 104832K,   0% used [...)
  to   space 104832K,   0% used [...)
 concurrent mark-sweep generation total 2097152K, used 623387K [...)
 Metaspace       used 352638K, capacity 487488K, committed 786432K, reserved 1775616K
  class space    used 36291K, capacity 40194K, committed 59988K, reserved 1048576K
}

Из того, что я вижу, емкость Metaspace даже не приближается к зафиксированному размеру (в данном случае -XX:MaxMetaspaceSize=768m). Поэтому я подозреваю, что фрагментация Metaspace приводит к тому, что распределитель не может найти новый фрагмент для нового загрузчика классов.

Я знаю о -XX:PrintFLSStatistics, но это относится только к CMS, а не к встроенной памяти.

Итак, мой вопрос: есть ли помощь по отладке, подобная PrintFLSStatistics, доступная для родной памяти Hotspot?

Это использует 64-разрядную виртуальную машину сервера Java HotSpot (TM) (25.45-b02) для linux-amd64 JRE (1.8.0_45-b14).


person mabi    schedule 20.08.2015    source источник


Ответы (2)


Я только что изучил реализацию Metaspace в HotSpot. Метапространство разделено на куски и управляется с помощью свободного списка. Таким образом, фрагментация действительно является возможной причиной вашей проблемы.

Я также просмотрел флаги HotSpot VM (-XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal), в релизной версии флага нет.

Однако в классе Metaspace есть метод dump(), который, кажется, запускается установкой флага -XX:+TraceMetadataChunkAllocation. Есть также -XX:+TraceMetavirtualspaceAllocation, который, похоже, вас заинтересует. Однако это флаги «разработки», означающие, что вам нужна отладочная версия виртуальной машины.

person loonytune    schedule 20.08.2015
comment
Хорошая находка, я создаю отладочную версию и пробую ее. - person mabi; 20.08.2015

Ответ @loonytune работает отлично, но я хочу предоставить немного больше деталей:

Для контекста, метапространство представляет собой набор метапространств, по одному на загрузчик классов. Каждое метапространство содержит список VirtualSpace объектов, из которых выделяются Metachunk объектов разных размеров. Эти фрагменты содержат MetaBlocks, которые являются настоящими контейнерами для метаданных.

Мне нужна отладочная JRE для запуска этих флагов, поэтому следуйте этому руководству Я проверил репозиторий openjdk (я переименовал кассу в vm, потому что скрипты сборки, похоже, имеют проблемы с именем папки jdk8), запустил

~/vm$ bash configure --enable-debug
~/vm$ DISABLE_HOTSPOT_OS_VERSION_CHECK=ok make all

и использовал полученный vm/build/linux-x86_64-normal-server-fastdebug/images/j2re-image в качестве среды выполнения Java.

Сгенерированные строки журнала выглядят следующим образом:

VirtualSpaceNode::take_from_committed() недоступно 8192 слова space @ 0x00007fee4cdb9350 128K, используется 94%

Это указывает на то, что текущий VirtualSpace заполнен и не может содержать другой фрагмент запрошенного размера 8192 word. Это заставит это метапространство переключиться на другое VirtualSpace.

ChunkManager::chunk_freelist_allocate: 0x00007fee4c0c39f8 чанк 0x00007fee15397400 размер 128 количество 0 Всего свободных чанков 7680 количество 15

ChunkManager::chunk_freelist_allocate: 0x00007fee4c0c39f8 чанк 0x00007fedf6021000 размер 512 количество 14 Всего свободных чанков 7168 количество 14

Это происходит, когда выделяется новый Metachunk, в первом случае он имеет размер 128 слов и использует список маленьких фрагментов. Как вы можете видеть, следующий запрос идет к блокам среднего размера (размером 512) и оставляет в общей сложности 14 блоков. Когда общее количество свободных ресурсов достигает 0, для увеличения общего размера метапространства требуется полный сборщик мусора.

Обратите внимание, что указание -verbose дает вам еще больше выходных данных от двух вышеуказанных флагов.

person mabi    schedule 20.08.2015