Статьи

Исследование утечек памяти. Часть 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. Откройте «Операции» и выберите dumpHeap. Теперь вы увидите операцию dumpHeap, которая принимает два параметра p0 и p1. Введите имя файла для дампа кучи в поле редактирования p0 и нажмите кнопку dumpHeap.

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

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

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

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

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

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

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

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

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

-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

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

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

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

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

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

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

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

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

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

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

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


1 Исходный код можно найти в моем
проекте Producer Consumer на GitHub .