Анализатор памяти Eclipse видит небольшую часть (363,2 МБ) всего дампа кучи (8 ГБ)
Я пытался расследовать java.lang.OutOfMemoryError: GC limit exceeded
что происходит при высокой нагрузке нашего веб-приложения, развернутого в tomcat. Размер кучи был установлен на 8 ГБ (-Xms2048m -Xmx8192m
)
В какой-то момент наше приложение перестает отвечать на запросы из-за активности GC. В журналах я видел, что Full GC происходил несколько раз подряд. Поэтому я взял дамп кучи с помощью следующей команды (jmap -F -dump:format=b,file=/root/dump2.hprof 4963
). Файл, содержащий дамп, был размером 9 ГБ. После того, как дамп был взят (приложение было заморожено в течение 45 минут), несколько полных сборок мусора происходили до OutOfMemoryError
был брошен.
Вот пример журнала активности GC
[Full GC [PSYoungGen: 932096K->875513K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6467961K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 12.3954040 secs] [Times: user=47.60 sys=0.43, real=12.39 secs]
[Full GC [PSYoungGen: 932096K->890562K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6483009K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 12.6131900 secs] [Times: user=48.45 sys=0.49, real=12.61 secs]
[Full GC [PSYoungGen: 932096K->895268K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6487715K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 12.9488670 secs] [Times: user=49.61 sys=0.46, real=12.95 secs]
Heap
PSYoungGen total 1864128K, used 896698K [0x0000000755560000, 0x0000000800000000, 0x0000000800000000)
eden space 932096K, 96% used [0x0000000755560000,0x000000078c10e8a8,0x000000078e3a0000)
from space 932032K, 0% used [0x000000078e3a0000,0x000000078e3a0000,0x00000007c71d0000)
to space 932032K, 0% used [0x00000007c71d0000,0x00000007c71d0000,0x0000000800000000)
ParOldGen total 5592448K, used 5592447K [0x0000000600000000, 0x0000000755560000, 0x0000000755560000)
object space 5592448K, 99% used [0x0000000600000000,0x000000075555ff30,0x0000000755560000)
PSPermGen total 262144K, used 112285K [0x00000005e0000000, 0x00000005f0000000, 0x0000000600000000)
object space 262144K, 42% used [0x00000005e0000000,0x00000005e6da7530,0x00000005f0000000)
heap dump is taken (ca 45minutes freeze)
[Full GC [PSYoungGen: 932096K->903362K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6495810K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 2883.9864390 secs] [Times: user=49.41 sys=0.47, real=2884.17 secs]
[Full GC [PSYoungGen: 932096K->897728K(1864128K)] [ParOldGen: 5592447K->5592444K(5592448K)] 6524543K->6490173K(7456576K) [PSPermGen: 112288K->112288K(262144K)], 13.3092680 secs] [Times: user=50.75 sys=0.40, real=13.31 secs]
Для анализа дампа кучи я открыл его в анализаторе памяти Eclipse (MAT). К сожалению, MAT показывает, что размер кучи был 363,2 МБ (на вкладке обзора или на вкладке сведений о дампе кучи), тогда как согласно журналам GC кучи были заполнены до 6467961 КБ (6,4 ГБ). Недостижимые объекты Гистограмма показывает всего 75 511 736 (75 МБ). Гистограмма также подтвердила, что общая мелкая куча была 380 837 136 (363,2 МБ)
Мой вопрос: почему MAT не отображает все объекты из дампа кучи, если GC не может восстановить память?
env details:
Eclipse Memory Analyzer Version 1.2.1
heap dump taken on
java version "1.7.0_13"
Java(TM) SE Runtime Environment (build 1.7.0_13-b20)
Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)
Вот скриншоты импортированного дампа кучи в MAT:
5 ответов
MAT не отображает недоступные объекты по умолчанию.
Вы можете включить эту опцию, выбрав "Настройки" -> "Анализатор памяти" -> "Сохранить недоступные объекты". Загрузите кучу снова, как только опция включена.
Он покажет полную кучу, как только опция включена. Даже я был в той же ситуации и не мог получить много информации в Интернете, и мой менеджер показал мне вариант. Надеюсь, это поможет.
По умолчанию MAT скрывает все недостижимые объекты из своих представлений, поскольку эти объекты уже помечены как сборщик мусора.
Недостижимые объекты можно сделать доступными в следующих представлениях:
- Закрыть снимок
- Выберите дамп кучи, нажав правой кнопкой мыши «Окно» > «История дампа кучи», Удалить файлы индекса.
- Выберите «Сохранить недоступные объекты», используя «Окно»> «Настройки»> «Анализатор памяти».
- Повторно откройте дамп кучи, который будет повторно анализировать дамп кучи.
- Выберите запрос Java Basics > GC Roots.
- Выберите строку «Недоступные объекты».
- Запустите запрос «Показать сохраненный набор» в этой строке.
Это покажет гистограмму всех объектов, которые обычно недоступны и будут удалены сборщиком мусора при следующей возможности. Поскольку эти объекты теперь находятся на снимке, их можно изучить более подробно.
Для получения подробной информации см. Справочник по Eclipse MAT — недоступные объекты .
Недавно мы обнаружили ошибку в MAT, когда она видела только часть кучи: https://bugs.eclipse.org/bugs/show_bug.cgi?id=404679
Проблема заключалась в том, что JVM записала одну запись HEAP_DUMP, которая была больше 4 ГБ и, следовательно, длина в заголовке завернута.
Какую версию MAT вы используете? Пожалуйста, попробуйте более свежую сборку.
Это обычное поведение MAT при сборе кучи такой большой кучи. Я часто собираю дампы кучи по 8 ГБ и обычно получаю профиль MAT, показывающий ~1 ГБ живых объектов.
Также ожидается заморозка на 45 минут. Мое объяснение состоит в том, что во время сбора дампа кучи происходит несколько циклов FullGC, которые уменьшают размер фактически полученного дампа кучи. Но я не нашел официального объяснения или справочной документации, почему такая большая разница.
Далее, смотрите эту ссылку - MAT не показывает полную кучу:
Симптом: при интерактивном мониторинге использования памяти размер используемой кучи намного больше, чем сообщает MAT.
Во время создания индекса анализатор памяти удаляет недостижимые объекты, потому что различные алгоритмы сборщика мусора имеют тенденцию оставлять некоторый мусор (если объект слишком мал, перемещение и переназначение адресов является дорогостоящим). Это должно быть, однако, не более 3-4 процентов. Если вы хотите знать, какие объекты удаляются, включите отладочный вывод, как описано здесь: MemoryAnalyzer / FAQ # Enable_Debug_Output
На самом деле, я не рекомендую использовать утилиту jmap при устранении неполадок java.lang.OutOfMemoryError: проблема превышения лимита ГХ. Я видел проблемы с этим подходом, в то время как JVM ломает (чрезмерное количество главных коллекций).
Пожалуйста, попробуйте следующий подход и посмотрите, получите ли вы лучшие результаты в процессе анализа и анализа MAT:
- Добавьте следующий параметр JVM HotSpot -XX:+HeapDumpOnOutOfMemoryError
- Повторите проблему снова и дождитесь события OOM. Генерация дампа кучи должна быть намного быстрее, что повысит ценность и достоверность данных.
- Затем JVM сгенерирует дамп кучи JVM (формат HPROF) после события OOM.
- Загрузите JVM Heap Dump снова в MAT и посмотрите, получите ли вы лучшие результаты, например, большую площадь кучи.
С уважением, PH