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

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

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

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

Ответ 1

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

  • Запустите приложение и подождите, пока он не достигнет "стабильного" состояния, когда вся инициализация завершена и приложение не работает.
  • Выполните операцию, предположительно, чтобы произвести утечку памяти несколько раз, чтобы разрешить любую кеш, связанную с DB инициализацию.
  • Запустите GC и сделайте снимок памяти.
  • Повторите операцию. В зависимости от сложности работы и размеров данных, которые обрабатываются, может потребоваться несколько раз.
  • Запустите GC и сделайте снимок памяти.
  • Запустите diff для двух снимков и проанализируйте его.

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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

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

Вот где картинка класса входит в картину. Вы можете сбросить гистограмму живого класса с помощью инструмента 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 distribution, G1GC

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

Ответ 9

Это можно узнать, измерив объем использования памяти после многократного вызова сборщика мусора:

Runtime runtime = Runtime.getRuntime();

while(true) {
    ...
    if(System.currentTimeMillis() % 4000 == 0){
        System.gc();
        float usage = (float) (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
        System.out.println("Used memory: " + usage + "Mb");
    }

}

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

Used memory: 14.603279Mb
Used memory: 14.737213Mb
Used memory: 14.772224Mb
Used memory: 14.802681Mb
Used memory: 14.840599Mb
Used memory: 14.900841Mb
Used memory: 14.942261Mb
Used memory: 14.976143Mb

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

Ответ 10

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