Куча отслеживания собственной памяти Java совершила намного больше, чем всего из дампа кучи

Используя jdk1.8.0_152, я пытаюсь отследить, какая часть моей Java-программы использует больше всего памяти (в основном в куче)

Используя top, я вижу, что весь процесс использует около 1,109 ГБ остаточной памяти.

Используя jcmd {PID} VM.native_memory, я вижу, что общий зарезервированный объем составляет 4704896 КБ, а зафиксированный - около 1290820 КБ. Committed - это немного больше, чем остаточная память, но я читал, что не вся зафиксированная память могла быть выгружена в фактическую память, поэтому меня не очень беспокоит эта разница.

Сейчас меня больше всего беспокоит разница между использованием памяти кучи из VM.native_memory и общим использованием кучи, когда я использую jcmd {PID} GC.class_histogram.

Я также попытался сравнить использование кучи, используя jstat -gc {PID}, и получил результаты, аналогичные GC.class_histogram

Согласно GC.class_histogram и jstat -gc, использование кучи составляет около 250 МБ, но использование VM.native_memory кучи (зафиксировано в разделе Java Heap) составляет около 1000000 КБ (то есть немного меньше 1 ГБ), но фактическая память RSS, похоже, ближе к общему объему, зафиксированному в VM.native_memory

Сейчас я предполагаю, что VM.native_memory Java Heap содержит память, которая не собиралась сборщиком мусора, но даже когда я запускаю сборку мусора, я вижу, что результат jstat -gc резко уменьшается, а VM.native_memory вообще не затрагивается (хотя я слышал, как пользователь вручную вызов сборки мусора не всегда приводит к полной сборке мусора, но, по крайней мере, кажется, что jstat -gc соответствует результату GC.class_histogram.

Еще я слышал, что остаточная память из top не всегда освобождается, когда процесс, использующий память, освобождает ее до тех пор, пока эта память не будет освобождена абсолютно.

Итак, чтобы подвести итог

  1. Почему VM.native_memory показывает другое использование памяти кучи, чем jstat и GC.class_histogram?
  2. Какую метрику мне следует использовать, чтобы узнать, сколько памяти использует мой Java-процесс? (учитывая, что остаточная память в top может не всегда отражать фактическое использование)

person markk    schedule 30.09.2019    source источник
comment
@Holger согласно docs.oracle.com/javase/ 8 / docs / technotes / guides / Troubleshoot / собственная память, похоже, относится ко всей памяти, которую использует виртуальная машина Java Hotspot, включая кучу, а также другую память, такую ​​как поток (стек), кеши классов и т. Д.   -  person markk    schedule 30.09.2019
comment
Понятно, значит, вы не понимаете, что «зафиксировано» не означает «используется» в смысле «заполнено объектами Java»?   -  person Holger    schedule 30.09.2019
comment
@Holger хм .. да если я вас правильно понял? но в соответствии с документацией говорится, что на самом деле используется только выделенная память. поэтому кажется, что следует использовать commit. Судя по тому, как общее количество совершенных похоже на то, что top говорит, что процесс использует, кажется, что следует использовать зафиксированные? (хотя остаточная память может относиться к общей памяти, заблокированной jvm, по сравнению с памятью, фактически заполненной объектами. Но, согласно принятой документации, похоже, относится к объектам, фактически заполняющим эту память)   -  person markk    schedule 30.09.2019
comment
Память, которая не была зафиксирована, очевидно, не используется. Однако память кучи, которая была использована, но стала свободной из-за сборки мусора, по-прежнему зафиксирована и будет повторно использована для последующих выделений. Возвращение памяти системе происходит редко, некоторые сборщики мусора никогда не вернут.   -  person Holger    schedule 30.09.2019
comment
@Holger, это звучит разумно, поскольку я помню, что читал об этой части ... значит ли это, что собственная память Java Heap всегда будет верхней границей того, сколько памяти фактически использует процесс (и в большинстве случаев это совокупная сумма всех выделенные объекты?) Другими словами, с точки зрения фактической памяти, которую потребляет Java-процесс, я должен ссылаться только на дамп кучи и другие части в отслеживании собственной памяти (например, стек, код, внутренняя и т. д.)? В таком случае, в каком сценарии будет полезен анализ committed?   -  person markk    schedule 30.09.2019
comment
Объем выделенной ОЗУ не обязательно должен быть верхним пределом, при необходимости могут быть попытки зафиксировать больше (хотя обычно перед попыткой еще фиксировать выполняется по крайней мере одна попытка сборки мусора). См. Также это резюме.   -  person Holger    schedule 30.09.2019


Ответы (1)


Я предполагаю, что ваша куча jvm была установлена ​​с размером диапазона.

собственный трекер памяти отображает размер памяти из представления ОС (что близко к команде top), а jstat отображается во внутренней перспективе из jvm.

это означает, что jvm будет запрашивать память из ОС (проверка из top), но действительно использовать ее или нет, зависит от нее самой (проверка по jstat или jmap).

person toien    schedule 14.08.2020