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



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



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



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

760   9  

9 ответов:

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

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

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

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

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

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

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

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

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

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

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

в этом случае, это помогает узнать свой путь вокруг файла дампа hprof.

поиск сайтов начинается. Это показывает, какие объекты используют больше всего памяти. Но объекты не сгруппированы вместе только по типу: каждая запись также включает в себя идентификатор" трассировки". Затем вы можете найти эту "трассировку nnnn", чтобы увидеть несколько верхних кадров стека, где был выделен объект. Часто, как только я вижу, где расположен объект, я нахожу ошибку, и я закончил. Кроме того, обратите внимание, что вы можете управлять тем, сколько кадров записывается в стек с помощью опций to-Xrunhprof.

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

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

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

большую часть времени в корпоративных приложениях заданная куча 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 live

jstat -gccause pid <optional time interval>

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

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

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

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

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

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

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

Comments

    Ничего не найдено.