Интерпретация данных 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.

Другие вопросы по тегам