Перейти к содержанию
Авторизация  
SmokiMo

Диагностика утечек памяти в Java

Рекомендуемые сообщения

В данной заметке я хочу показать каким образом можно определять и устранять утечки памяти в Java на примере из моей повседневной работы. Мы не будем здесь рассматривать возможные причины появления утечек, об этом будет отдельная статья, так как тема достаточно обширная. Стоит заметить, что речь пойдет о диагностике именно Heap Memory, об утечках в других областях памяти будет отдельная статья.
 
Инструменты
  • Для успешной диагностики нам понадобятся два инструмента: Java Mission Control (jmc) и Eclipse Memory Analyzer. Вобщем-то можно обойтись только Memory Analyzer, но с JMC картина будет более полной.
  • JMC входит в состав JDK (начиная с 1.7)
  • Memory Analyzer может быть загружен отсюда: MAT
Анализ использования памяти
  • Прежде всего, нужно запустить приложение со следующими флагами JVM:
-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder
  • Не используйте эти опции на production системе без приобретения специальной лицензии Oracle!
  • Эти опции позволят запустить Flight Recorder – утилита, которая поможет собрать информацию об использовании памяти (и много другой важной информации) во время выполнения программы. Я не буду описывать здесь как запустить Flight Recorder, эта информация легко гуглится. В моем случае было достаточно запустить FR на 10-11 минут.

Рассмотрим следующий рисунок, на котором показана классическая «пила» памяти, а так же важный сигнал, что что-то не так с использованием памяти:

 
23de062e4e46c5045c8843d124936242.png
 
Можно увидеть, что после каждого цикла очистки памяти, heap все больше заполняется, я выделил это желтым треугольником. «Пила» все время как бы ползет вверх. Это значит, что какие-то объекты не достижимы для очистки и накапливаются в old space, что со временем приведет к переполнению этой области памяти.
 
Выявление утечки
 
Следующим шагом нужно выявить, что именно не доступно для очистки и в этом нам поможет Memory Analyzer. Прежде всего, нужно загрузить в программу heap dump работающего приложения с предполагаемой утечкой памяти. Это можно сделать с помощью «File → Acquire Heap Dump». После загрузки в диалоге «Getting Started Wizard» выбрать «Leak Suspects Report» после этого откроется краткий обзор возможных утечек памяти:
 
31de9b8dc755aaa39b9ad286a800698f.png
 
Если вернуться на вкладку «Overview» и выбрать «Dominator Tree», то можно увидеть более подробную картину:
 
7bafd3a750c8fda317c27ea8fed15239.png
fc546750208202d6318dfa4b795306cc.png
 
Дерево показывает структуру «тяжелого» объекта, а так же размер его полей (по типу). Можно видеть, что одно из полей объекта MasterTenant занимает более 45% памяти.
 
Устранение утечки
  • Имея результат анализа из предыдущего пункта, следующим шагом идет устранение накапливания объектом памяти. Тут все сильно зависит от конкретного кода. Общая рекоменация – нужно найти и проанализировать все места, где происходит инициализация или изменение соответствующего поля или полей, чтобы понять механизм накапливания памяти. В моем случае в коллекцию постоянно добавлялись записи из множества (около 150) потоков при определенных условиях.
  • После находжения и устранения утечки, не лишним будет пройти все шаги снова, проанализировать память и отчет Memory Analyzer, чтобы убедиться что фикс помог.

Ссылка на оригинал

  • Upvote 6

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пользуюсь VisualVM куда лучше и удобней, а так сути не меняет.

Хотел бы в добавок подкрепить ещё статейку.

http://learn.javajoy.net/java-memory-leaks

Да, с этой статьей тоже знаком, хотел и ее добавить

  • Upvote 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это значит, что какие-то объекты не достижимы для очистки и накапливаются в old space, что со временем приведет к переполнению этой области памяти.

 

Я не согласен с этим, если объект попал в old space, это не значит что его нельзя очистить, это значит лишь то, что объект пережил чистки, и не нуждается пока что в чистке. Но как только дело подойдет к пределу old gen, и его будет мало, он будет запускать полную очистку, шерстя по old space. Более точная инфа вроде вот тут. http://netflix.github.io/spectator/en/latest/ext/jvm-gc-causes/

Обычно сразу чистятся локальные ссылки.

 

YourKit либо на крайний случай можно использовать VisualVM, но на сколько я помню, он не сохраняет показания которые пришла. В отличии от YourKit

Изменено пользователем Mangol

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

как только дело подойдет к пределу old gen, и его будет мало, он будет запускать полную очистку

Не совсем: FullGC не всегда вызывается, когда места в oldgen не хватает (кстати говоря, он же и переносит из элдена в олд объекты). Зависит чуть более чем полностью от подключенного GC и выставленных настроек поколений/сборщика/etc. У CMS, вообще, еще больше типов поколений объектов хипа (а также в его замене, которая придет в Java 9). G1 - разбивает весь хип на чанки и чистятся чанки, а не сразу все старое поколение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не совсем: FullGC не всегда вызывается, когда места в oldgen не хватает (кстати говоря, он же и переносит из элдена в олд объекты). Зависит чуть более чем полностью от подключенного GC и выставленных настроек поколений/сборщика/etc. У CMS, вообще, еще больше типов поколений объектов хипа (а также в его замене, которая придет в Java 9). G1 - разбивает весь хип на чанки и чистятся чанки, а не сразу все старое поколение.

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

Ну все верно. G1 создает ячейки, по дефолту их около 2 тысяч на сколько я помню. Ну так оракл гласит по доке. Так же он отдельно большие части ложит отдельно. Ну, и самое приятно что он более точно прогнозирует STW в отличии от предыдущих поколений, и старается вложится в это время.

Да и вообще, он может вызывать фулл, не только когда в old gen не хватает памяти. В G1 всё разбито на множество ячеек, что довольно умно в отличии от предыдущих поколений GC.(Parralel, CMS),ну самое первое поколение думаю скоро выпилят. Пока по дефолту java 8 использует Parralel.

Изменено пользователем Mangol

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация  

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...