Это почти невозможно без понимания базового кода. Если вы понимаете лежащий в основе код, то сможете лучше отделять зерна от плевел в миллионах битов информации, которые вы получаете в своих кучных дампах.
Кроме того, вы не можете знать, является ли что-то утечкой или нет, не зная, почему класс существует в первую очередь.
Я провел последние пару недель, делая именно это, и я использовал итеративный процесс.
Во-первых, я обнаружил, что профилировщики кучи практически бесполезны. Они не могут эффективно анализировать огромные кучи.
Скорее, я почти полностью полагался на гистограммы jmap. .
Я полагаю, вы знакомы с ними, но для тех, кто нет:
jmap -histo:live <pid> > dump.out
создает гистограмму живой кучи. В двух словах, он сообщает вам имена классов и количество экземпляров каждого класса в куче.
Я сбрасывал кучу регулярно, каждые 5 минут, 24 часа в сутки. Возможно, это слишком подробно для вас, но суть та же.
Я провел несколько различных анализов этих данных.
Я написал скрипт, который берет две гистограммы и выводит разницу между ними. Таким образом, если java.lang.String было равно 10 в первом дампе и 15 во втором, мой сценарий выдал бы «5 java.lang.String», сообщая мне, что он увеличился на 5. Если он уменьшился, число было бы отрицательным.
Затем я брал несколько таких отличий, удалял все классы, которые переходили от одного запуска к другому, и объединял результат. В конце у меня был бы список классов, который постоянно рос в течение определенного промежутка времени. Очевидно, что это первые кандидаты на утечку классов.
Тем не менее, некоторые классы сохранились, а другие были GC. Эти классы могут легко повышаться и понижаться в целом, но все равно будут протекать. Таким образом, они могли выпасть из категории «всегда повышающихся» классов.
Чтобы найти их, я преобразовал данные во временные ряды и загрузил их в базу данных, в частности в Postgres. Postgres удобен тем, что предлагает статистические агрегатные функции., поэтому вы можете выполнить простой анализ линейной регрессии данных и найти классы, которые тенденция вверх, даже если они не всегда на вершине диаграммы. Я использовал функцию regr_slope, ища классы с положительным наклоном.
Я нашел этот процесс очень успешным и действительно эффективным. Файлы гистограмм не так уж велики, и их было легко скачать с хостов. Они не были слишком дорогими для запуска в производственной системе (они требуют большого GC и могут немного заблокировать виртуальную машину). Я запускал это в системе с кучей Java 2G.
Теперь все, что он может сделать, это определить классы с потенциальной утечкой.
Здесь важно понять, как используются классы и должны ли они быть их собственными.
Например, вы можете обнаружить, что у вас много классов Map.Entry или какой-то другой системный класс.
Если вы просто не кэшируете String, дело в том, что эти системные классы, хотя, возможно, и «нарушители», не являются «проблемой». Если вы кэшируете какой-то класс приложения, ЭТОТ класс является лучшим индикатором того, в чем заключается ваша проблема. Если вы не кэшируете com.app.youurbean, у вас не будет связанной с ним Map.Entry.
Когда у вас есть несколько классов, вы можете начать сканирование базы кода в поисках экземпляров и ссылок. Поскольку у вас есть собственный уровень ORM (хорошо это или плохо), вы можете, по крайней мере, легко просмотреть его исходный код. Если вы ORM кешируете материал, скорее всего, кеширует классы ORM, обертывающие классы вашего приложения.
Наконец, еще одна вещь, которую вы можете сделать, — это когда вы знаете классы, вы можете запустить локальный экземпляр сервера с гораздо меньшей кучей и меньшим набором данных и использовать для этого один из профилировщиков.
В этом случае вы можете выполнить модульное тестирование, которое затронет только 1 (или небольшое количество) вещей, которые, по вашему мнению, могут утечь. Например, вы можете запустить сервер, запустить гистограмму, выполнить одно действие и снова запустить гистограмму. Ваш просачивающийся класс должен был увеличиться на 1 (или какова ваша единица работы).
Профилировщик может помочь вам отследить владельцев этого «теперь просочившегося» класса.
Но, в конце концов, вам нужно иметь некоторое представление о вашей кодовой базе, чтобы лучше понять, что является утечкой, а что нет, и почему объект вообще существует в куче, не говоря уже о том, почему он может быть сохранен. как утечка в вашей куче.
person
Will Hartung
schedule
24.03.2010