Вопрос

Как обнаружить утечку памяти в Java (с помощью, например, JHat)?Я попытался загрузить дамп кучи в JHat, чтобы посмотреть на него в общих чертах.Однако я не понимаю, как мне найти корневую ссылку (ссылка) или как это называется.По сути, я могу сказать, что существует несколько сотен мегабайт записей хеш-таблицы ([java.util.HashMap$Entry или что-то в этом роде), но карты используются повсюду...Есть ли какой-нибудь способ поиска больших карт или, возможно, поиска общих корней больших деревьев объектов?

[Редактировать] Хорошо, я уже прочитал ответы, но давайте просто скажем, что я дешевый ублюдок (то есть мне больше интересно научиться использовать JHat, чем платить за JProfiler).Кроме того, JHat всегда доступен, поскольку он является частью JDK.Если, конечно, с JHat нет другого выхода, кроме грубой силы, но я не могу поверить, что такое может быть.

Кроме того, я не думаю, что смогу реально изменить (добавив журналирование все размеры карты) и запускайте его достаточно долго, чтобы я заметил утечку.

Это было полезно?

Решение

Я использую следующий подход к поиску утечек памяти в Java.Я с большим успехом использовал jProfiler, но считаю, что подойдет любой специализированный инструмент с возможностями построения графиков (разницы легче анализировать в графической форме).

  1. Запустите приложение и подождите, пока оно перейдет в «стабильное» состояние, когда вся инициализация будет завершена и приложение будет бездействовать.
  2. Запустите операцию, предположительно вызывающую утечку памяти, несколько раз, чтобы разрешить инициализацию кэша и БД.
  3. Запустите GC и сделайте снимок памяти.
  4. Запустите операцию еще раз.В зависимости от сложности операции и размеров обрабатываемых данных операцию может потребоваться выполнить от нескольких до многих раз.
  5. Запустите GC и сделайте снимок памяти.
  6. Запустите разницу для двух снимков и проанализируйте ее.

По сути, анализ следует начинать с наибольшего положительного различия, скажем, по типам объектов, и выяснять, что заставляет эти дополнительные объекты застревать в памяти.

Для веб-приложений, обрабатывающих запросы в несколько потоков, анализ усложняется, но, тем не менее, общий подход по-прежнему применим.

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

Другие советы

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

Поскольку люди предлагают несколько инструментов (я пробовал только Visual wm, так как я получил его в пробной версии JDK и JProbe), я решил предложить бесплатный инструмент с открытым исходным кодом, созданный на платформе Eclipse, анализатор памяти (иногда называемый SAP-памятью). анализатор) доступен на http://www.eclipse.org/mat/ .

Что действительно здорово в этом инструменте, так это то, что он проиндексировал дамп кучи, когда я впервые его открыл, что позволило ему отображать данные в виде сохраненной кучи, не дожидаясь 5 минут для каждого объекта (почти все операции выполнялись на тонны быстрее, чем другие инструменты, которые я пробовал). .

Когда вы открываете дамп, на первом экране отображается круговая диаграмма с самыми большими объектами (с учетом оставшейся кучи), и можно быстро перейти к объектам, которые слишком велики для удобства.В нем также есть функция «Найти вероятных подозреваемых в утечке», которая, как я считаю, может пригодиться, но, поскольку мне было достаточно навигации, я не особо вникал в нее.

Инструмент – это большая помощь.

Однако бывают случаи, когда использовать инструмент невозможно:дамп кучи настолько велик, что приводит к сбою инструмента, вы пытаетесь устранить неполадки на машине в какой-то производственной среде, к которой у вас есть доступ только к оболочке, и т. д.

В этом случае полезно разобраться с файлом дампа hprof.

Найдите САЙТЫ НАЧИНАЮТСЯ.Это показывает, какие объекты используют больше всего памяти.Но объекты не объединяются исключительно по типу:каждая запись также включает идентификатор «следа».Затем вы можете выполнить поиск по запросу «TRACE nnnn», чтобы увидеть несколько верхних кадров стека, в которых был выделен объект.Часто, как только я вижу, где расположен объект, я обнаруживаю ошибку, и все готово.Также обратите внимание, что вы можете контролировать количество кадров, записываемых в стек, с помощью параметров -Xrunhprof.

Если вы проверите сайт размещения и не увидите ничего плохого, вам придется начать обратную цепочку от некоторых из этих живых объектов к корневым объектам, чтобы найти неожиданную цепочку ссылок.Здесь действительно помогает инструмент, но вы можете сделать то же самое вручную (ну, с помощью grep).Существует не один корневой объект (т. е. объект, не подлежащий сборке мусора).Потоки, классы и кадры стека действуют как корневые объекты, и все, на что они сильно ссылаются, не подлежит сбору.

Чтобы выполнить цепочку, найдите в разделе HEAP DUMP записи с неверным идентификатором трассировки.Это приведет вас к записи OBJ или ARR, которая показывает уникальный идентификатор объекта в шестнадцатеричном формате.Найдите все вхождения этого идентификатора, чтобы определить, у кого есть сильная ссылка на объект.Следуйте по каждому из этих путей назад, пока они не разветвляются, пока не выясните, где находится утечка.Видите, почему этот инструмент так удобен?

Статические члены являются постоянными виновниками утечек памяти.Фактически, даже без инструмента стоило бы потратить несколько минут на поиск статических элементов Map в вашем коде.Может ли карта стать большой?Что-нибудь когда-нибудь очищает свои записи?

В большинстве случаев в корпоративных приложениях размер кучи Java превышает идеальный размер (максимум 12–16 ГБ).Мне было сложно заставить профилировщик NetBeans работать непосредственно с этими большими Java-приложениями.

Но обычно в этом нет необходимости.Вы можете использовать утилиту jmap, поставляемую с jdk, для создания «живого» дампа кучи, то есть jmap будет сбрасывать кучу после запуска GC.Выполните какую-нибудь операцию в приложении, подождите, пока операция завершится, а затем создайте еще один «живой» дамп кучи.Используйте такие инструменты, как Eclipse MAT, чтобы загрузить дампы кучи, отсортировать гистограмму, посмотреть, какие объекты увеличились или какие являются самыми высокими. Это даст подсказку.

su  proceeuser
/bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process)

У этого подхода есть только одна проблема;Огромные дампы кучи, даже с опцией live, могут быть слишком большими, чтобы их можно было перенести на этап разработки, и для их открытия может потребоваться машина с достаточным количеством памяти/ОЗУ.

Именно здесь на сцену выходит гистограмма классов.Вы можете сбросить гистограмму живого класса с помощью инструмента jmap.Это даст только гистограмму использования памяти классом. По сути, у нее не будет информации для связывания ссылки.Например, он может поместить массив символов вверху.И класс String где-то ниже.Вы должны сами установить связь.

jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt

Вместо двух дампов кучи возьмите две гистограммы классов, как описано выше;Затем сравните гистограммы классов и посмотрите, какие классы увеличиваются.Посмотрите, сможете ли вы связать классы Java с классами вашего приложения.Это даст довольно хорошую подсказку.Вот скрипт Pythons, который поможет вам сравнить два дампа гистограммы jmap. гистограммапарсер.py

Наконец, такие инструменты, как JConolse и VisualVm, необходимы для отслеживания роста объема памяти с течением времени и выявления утечек памяти.Наконец, иногда ваша проблема может быть не в утечке памяти, а в ее высоком использовании. Для этого включите ведение журнала GC; используйте более совершенный и новый GC для сжатия, например G1GC;и вы можете использовать инструменты jdk, такие как jstat, чтобы увидеть поведение GC в реальном времени.

jstat -gccause pid <optional time interval>

Другие ссылки на Google для -jhat, jmap, Full GC, огромного распределения, G1GC.

Существуют инструменты, которые помогут вам найти утечку, например JProbe, YourKit, AD4J или JRockit Mission Control.Последнее я лично знаю лучше всего.Любой хороший инструмент должен позволять вам детализироваться до уровня, на котором вы можете легко определить, какие утечки и где расположены объекты утечки.

Использование HashTables, Hashmaps и т.п. — один из немногих способов вообще утечки памяти в Java.Если бы мне пришлось искать утечку вручную, я бы периодически распечатывал размер своих HashMaps и оттуда находил тот, в который добавляю элементы и забывал их удалить.

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

NetBeans имеет встроенный профилировщик.

Вам действительно нужно использовать профилировщик памяти, который отслеживает распределение.Взгляни на JПрофилер - их функция «обхода к куче» великолепна, и они интегрируются со всеми основными Java IDE.Это не бесплатно, но и не так уж и дорого (499 долларов за одну лицензию) — вы довольно быстро потратите 500 долларов времени, пытаясь найти утечку с помощью менее сложных инструментов.

возможно, вы захотите проверить jконсоль.Это также часть JDK, и я нашел полезным находить утечки памяти/ссылок в сочетании с jhat.Также взгляните на этот запись в блоге.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top