Мне было поручено отладить приложение Java (J2SE), которое после некоторого периода активности начинает выдавать исключения OutOfMemory. Я новичок в Java, но имею опыт программирования. Мне интересно узнать ваше мнение о том, какой может быть хороший подход к диагностике такой проблемы?
До сих пор я использовал JConsole, чтобы получить представление о том, что происходит. У меня есть подозрение, что есть объекты, которые не выпускаются должным образом и поэтому не очищаются во время сборки мусора.
Есть ли какие-нибудь инструменты, которые я мог бы использовать, чтобы получить представление об экосистеме объекта? С чего бы вы начали?




Я бы начал с правильного профилировщика Java. JConsole бесплатна, но далеко не так полнофункциональна, как те, которые стоят денег. Я использовал JProfiler, и он того стоил. Смотрите https://stackoverflow.com/questions/14762/please-recommend-a-java-profiler для получения дополнительных опций и мнений.
Попробуйте Анализатор памяти Eclipse или любой другой инструмент, который может обрабатывать дамп кучи java, а затем запустите приложение с клапаном, который создает дамп кучи, когда у вас заканчивается память.
Затем проанализируйте дамп кучи и найдите подозрительно большое количество объектов.
См. Эту статью для получения дополнительной информации о свалка кучи.
Обновлено: Также обратите внимание, что вашему приложению может законно потребоваться больше памяти, чем вы изначально думали. Вы можете сначала попробовать увеличить минимальное и максимальное выделение памяти java до чего-то значительно большего и посмотреть, будет ли ваше приложение работать бесконечно или просто будет немного дальше.
Я хотел бы дать прямую ссылку на мой комментарий о EMA в другом потоке, но я не могу рекомендовать это достаточно. EMA может открыть файл журнала дампа кучи размером ~ 400 МБ менее чем за 5 минут для меня, в то время как jhat потребовалось более 70 минут, чтобы прочитать его, прежде чем он разбил JVM (никогда не мог даже открыть его полностью).
http://www.yourkit.com/download/index.jsp - единственный инструмент, который вам понадобится. Вы можете делать снимки в (1) время запуска приложения и (2) после запуска приложения в течение N промежутков времени, а затем сравнивать снимки, чтобы увидеть, где выделяется память. Он также сделает снимок OutOfMemoryError, чтобы вы могли сравнить этот снимок с (1).
Например, последний проект, который мне пришлось устранять, выдавал исключения OutOfMemoryError, и после запуска YourKit я понял, что большая часть памяти на самом деле была выделена некоторому классу ehcache "LFU", причем мы указали множество определенных POJO, которые должны быть кэшируется в памяти, но мы не указываем достаточно -Xms и -Xmx (начальное и максимальное распределение памяти JVM).
Я также использовал Linux vmstat, например. на некоторых платформах Linux просто не включено достаточно подкачки или не выделяются непрерывные блоки памяти, и тогда есть jstat (в комплекте с JDK).
ОБНОВИТЬ см. https://stackoverflow.com/questions/14762/please-recommend-a-java-profiler
Вы также можете добавить «UnhandledExceptionHandler» в поток вашего приложения. Это перехватит «неперехваченное» исключение, такое как ошибка нехватки памяти, и вы, по крайней мере, будете иметь представление о том, где возникло исключение. Обычно проблема заключалась не в этом, а в «новом», которое не могло быть удовлетворено. Как правило, я всегда добавляю UnhandledExceptionHandler в поток, если больше нечего добавлять в журнал.
Последняя версия Sun JDK включает VisualVM, который, по сути, сам по себе является профилировщиком Netbeans. Это действительно хорошо работает.
Спасибо за внимание. Примерно через 30 минут, потраченных на настройку интеграции профилировщика, я смог найти источник утечки памяти примерно за 5 минут. Оцените предложение.