Статьи

Исследование утечек памяти. Часть 2. Анализ проблемы

В первом блоге этой мини-серии рассказывалось о создании очень неплотного примера приложения, чтобы мы могли исследовать методы решения проблем с кучей в серверных приложениях. Это демонстрирует большую проблему с шаблоном Producer-Consumer, а именно то, что потребительский код должен иметь возможность удалять элементы из очереди по крайней мере так же быстро, если не быстрее, чем производитель. Блог закончился тем, что я запустил пример кода и откинулся на спинку кресла, пока у него не осталось достаточно памяти для расследования. Пришло время заняться этим расследованием.

Если вы прочтете первую часть этого блога , то узнаете, что код с утечкой является частью приложения 1, которое записывает заказы на акции / акции в фиктивную базу данных с использованием шаблона Producer Consumer. Пример кода был написан так, чтобы содержать очень очевидный недостаток, а именно то, что OrderRecord не может идти в ногу с OrderFeed . Это означает, что очередь Order становится все больше и больше, пока, наконец, приложение не исчерпает пространство кучи и не упадет. Дело в том, что, глядя на мой простой код, проблема должна быть очевидной, но что, если вы никогда не видели код раньше, и это огромный, сложный промышленный код, плюс нет простого потока мониторинга, чтобы следить за размером очереди или другие внутренние органы? Что вы делаете тогда?

Это три шага, необходимые для поиска проблемы с негерметичным приложением:

  1. Возьми дамп кучи текущего сервера.
  2. Используйте дамп кучи для создания отчета.
  3. Проанализируйте отчет.

Есть несколько инструментов, которые вы можете использовать для создания файла дампа кучи. Они включают:

  1. JConsole
  2. jvisualvm
  3. Eclipse Memory Analyzer Tool (MAT)

Взятие дампа кучи с помощью jconsole

Подключите jconsole к вашему приложению. Нажмите на вкладку MBeans и откройте пакет com.sun.management . Затем нажмите на HotSpotDiagnostic . Откройте « Operations и выберите dumpHeap . Теперь вы увидите операцию dumpHeap , которая принимает два параметра p0 и p1 . Введите имя файла для дампа кучи в поле редактирования p0 и нажмите кнопку dumpHeap.

invest1

Принимая кучу дамп с jvisualvm

При подключении к образцу кода щелкните правой кнопкой мыши свое приложение на левой панели «приложения» и выберите «Дамп кучи».

Обратите внимание, что если у вас есть удаленное подключение к вашему негерметичному серверу, jvisualvm сохранит файл дампа в каталоге /tmp удаленного компьютера (при условии, что это окно Unix). Вам придется отправить этот файл по FTP на ваш компьютер для дальнейшего анализа.

invest2

Взятие свалки с MAT

Хотя jconsole и jvisualvm являются частью инструмента JDK, MAT или анализатора памяти, это инструмент, основанный на затмении, который можно загрузить с eclipse org

Текущая версия MAT требует, чтобы на вашем компьютере был установлен 1.6 jdk. Если вы используете Java 1.7, не беспокойтесь, он установит 1.6 для вас и не испортит остальную часть вашего компьютера и версию 1.7 по умолчанию.

invest3

При использовании MAT нужно нажимать на «Aquire Heap Dump» и следовать инструкциям.

invest4

Удаленные подключения

Здесь следует отметить, что если вы пытаетесь выяснить, почему рабочий сервер падает, то вам, вероятно, придется подключиться удаленно, используя JMX, и для этого вам понадобятся следующие параметры командной строки, которые я повторил из моего предыдущего блога:

1
2
3
4
5
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Когда брать свалку

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

invest5

Лучше всего присоединить jconsole к вашему приложению и отслеживать его кучу, пока он не окажется на грани краха. Это легко заметить, поскольку все три индикатора кучи зеленого цвета:

invest6

Анализ дампа кучи

Вот тут-то и выходит MAT, поскольку он был разработан для анализа дампов кучи. Чтобы открыть и проанализировать дамп кучи, выберите File | Open Heap Dump File | Open Heap Dump После выбора файла дампа кучи вам будет предложено три варианта, как показано ниже:

invest7

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

invest8

Круговая диаграмма демонстрирует, что в этом случае есть один главный подозреваемый утечка. Возможно, вы думаете, что это немного исправлено, ведь это пример кода, что вы ожидаете? Ну, да, в этом случае это очень ясно; подозреваемый «а» занимает 98,7 МБ, в то время как остальные объекты в памяти используют другие 1,5 МБ. Дело в том, что вы получаете круговые диаграммы с подозрением на утечку в реальных ситуациях, которые выглядят следующим образом.

Следующее, что нужно сделать, это копать немного глубже …

invest9

Следующая часть отчета, показанная выше, говорит нам, что существует LinkedBlockingQueue который использует 98,46% памяти. Для дальнейшего изучения, нажмите Details>> .

invest10

Это показывает, что проблема действительно заключается в нашем orderQueue , к которому обращаются три объекта из моего предыдущего блога : OrderFeed , OrderRecord и OrderMonitor и, как мы знаем из кода, содержит целую кучу объектов Order .

Ну это все; MAT сказал нам, что у примера кода есть LinkedBlockingQueue который использует все пространство кучи примера приложения, что вызывает огромные проблемы. Он не сказал нам, почему это происходит, и вы не можете этого ожидать. Это вопрос, как сказал бы Эркюль Пуаро Агаты Кристи , используя «маленькие серые клетки»…