Интерпретация данных jemaloc возможной утечки из кучи
Я начал поиски 2 недели назад для постоянно растущей памяти Java. Я использую следующую команду для предотвращения чрезмерного роста кучи, а также для выполнения некоторой отладки.
Я работаю на Ubuntu 16.04, используя oracle java 8, так как openjdk 8 не имел отладочных символов, необходимых для того, чтобы jemaloc предоставлял правильные данные
-XX:NativeMemoryTracking=detail -XX:+UseG1GC -XX:+UseStringDeduplication -Xms64m -Xmx256m -XX:MaxMetaspaceSize=128m -Xss256k
Как видите, мой Xmx установлен на 256м. тем не мение top
в настоящее время показывает мой процесс на 1.1G
После использования JProfiler и JVisualVm я и многие другие вещи, которые я смог найти в Google, я пришел к выводу, что это должно быть проблема вне кучи.
После долгих поисков я наткнулся jemaloc
и статьи, которые я читал об этом, казались многообещающими. Но у меня возникли проблемы с интерпретацией этих данных. И выяснить, как точно определить источник моей проблемы.
максимальное использование памяти
Собственные данные отслеживания памяти
Native Memory Tracking:
Total: reserved=1678MB, committed=498MB
- Java Heap (reserved=256MB, committed=256MB)
(mmap: reserved=256MB, committed=256MB)
- Class (reserved=1103MB, committed=89MB)
(classes #14604)
(malloc=3MB #32346)
(mmap: reserved=1100MB, committed=85MB)
- Thread (reserved=26MB, committed=26MB)
(thread #53)
(stack: reserved=26MB, committed=26MB)
- Code (reserved=261MB, committed=96MB)
(malloc=17MB #17740)
(mmap: reserved=244MB, committed=79MB)
- GC (reserved=1MB, committed=1MB)
(mmap: reserved=1MB, committed=1MB)
- Internal (reserved=6MB, committed=6MB)
(malloc=6MB #48332)
- Symbol (reserved=19MB, committed=19MB)
(malloc=16MB #168491)
(arena=4MB #1)
- Native Memory Tracking (reserved=5MB, committed=5MB)
(tracking overhead=4MB)
0 ответов
Проверьте карту памяти процесса
Собственное отслеживание памяти учитывает только структуры виртуальной машины Java, но не учитывает отображенные в памяти файлы и собственную память, выделенную общими библиотеками (включая собственный код библиотеки классов Java). Кроме того, NMT не отслеживает какую-либо внутреннюю фрагментацию malloc
стандартный распределитель libc.
Во-первых, чтобы проанализировать использование Java-процесса вне кучи, рассмотрим его полную карту памяти:
pmap -X <pid>
Это позволит пролить свет на то, используется ли память сопоставленными файлами или анонимными областями.
Изменить стандартный распределитель
Если вы видите количество анонимных областей размером до 64 МБ, это может быть признаком маллок-арен. Известно, что libc malloc имеет проблемы с чрезмерным использованием виртуальной памяти в некоторых системах. С помощью jemalloc
или же tcmalloc
В этом случае решение может стать заменой (даже без функции профилирования).
Профиль собственных выделений
К сожалению, профилировщик jemalloc ничего не знает о Java; график разбивается на последнюю нативную функцию, поэтому вывод может выглядеть запутанным. В вашем случае jemalloc предполагает, что проблема может быть связана с загрузкой классов и System.loadLibrary
, но трудно сказать наверняка без полной картины.
Async-profiler позволяет отслеживать собственные размещения в контексте Java. Бежать
./profiler.sh -d <duration> -e malloc -f malloc.svg <pid>
Это даст График Пламени malloc
звонки, например:
Это всего лишь пример, демонстрирующий, как java.util.zip.GZIPOutputStream
может быть источником выделения собственной памяти. Ваш случай, конечно, будет другим.
Обратите внимание, что malloc
сами звонки не означают утечку памяти. Например, память может быть выделена, а затем освобождена вскоре после этого. График - это просто подсказка, где можно посмотреть.
Чтобы найти места, где RSS увеличивается, вы можете проследить mprotect
или же mmap
звонки. Это можно сделать с помощью async-profiler аналогичным образом:
./profiler.sh -d <duration> -e mprotect -f mprotect.svg <pid>
./profiler.sh -d <duration> -e mmap -f mmap.svg <pid>
Обратите внимание на агентские библиотеки
я заметил cbClassPrepare
а также classTrack_processUnloads
функции в вашем графе jemalloc. Это означает, что вы используете jdwp
агент отладки. Это может быть определенно причиной чрезмерного выделения памяти - я видел утечки памяти в jdwp
до. Любая другая агентская библиотека, включенная через -agentlib
, -agentpath
или же -javaagent
Параметры также подозрительны, так как их собственное использование памяти не отслеживается JVM.