Как найти утечку памяти Java - PullRequest
       54

Как найти утечку памяти Java

134 голосов
/ 02 сентября 2008

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

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

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

Ответы [ 9 ]

121 голосов
/ 02 сентября 2008

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

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

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

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

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

48 голосов
/ 11 сентября 2008

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

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

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

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

12 голосов
/ 02 сентября 2008

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

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

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

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

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

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

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

10 голосов
/ 24 июня 2015

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

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

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. histogramparser.py

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

jstat -gccause pid <optional time interval>

Другие ссылки на google для -jhat, jmap, Full GC, Humongous selection, G1GC

5 голосов
/ 02 сентября 2008

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

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

4 голосов
/ 02 сентября 2008

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

1 голос
/ 02 сентября 2008

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

0 голосов
/ 02 сентября 2008

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

0 голосов
/ 02 сентября 2008

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

...