Обнаружение утечки памяти программно - PullRequest
7 голосов
/ 25 ноября 2010

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

Runtime.getRuntime().freeMemory()

начинает колебаться от 1 до 2 МБсвободной памяти.

Затем приложение входит в цикл, который выглядит следующим образом: сборщик мусора, обработка некоторых данных, сборщик мусора и т. д., но поскольку сборщик мусора происходит так часто, приложение в основном больше ничего не делает.Даже GUI требует времени, чтобы ответить (и, нет, я не говорю о проблемах EDT здесь, это - действительно VM, в основном застрявшая в некотором бесконечном режиме GC'ing).

И мне было интересно: есть лиспособ программно определить, что JVM больше не имеет достаточно памяти?

Обратите внимание, что я не говорю об ошибках памяти или об обнаружении утечки памяти.

Я говорю об обнаружении того, что у приложения настолько мало памяти, что оно в основном все время вызывает GC, почти не оставляя времени для выполнения чего-либо еще (в моем гипотетическом примере: обработка данных).

Будет ли работать, например, многократно читать, сколько памяти доступно, скажем, в течение одной минуты, и видеть, что, если число «колеблется» между различными значениями все ниже, скажем, 4 МБ, сделать вывод, что произошла утечкаи что приложение стало непригодным для использования?

Ответы [ 7 ]

3 голосов
/ 25 ноября 2010

И мне было интересно: есть ли способ программно обнаружить, что JVM больше не хватает памяти?

Я так не думаю.Вы можете приблизительно узнать, сколько памяти кучи свободно в любой момент, но, AFAIK, вы не можете точно определить, когда у вас заканчивается память.(Конечно, вы можете делать такие вещи, как очистка лог-файлов GC или пытаться выбрать шаблоны в колебаниях свободной памяти. Но они, вероятно, будут ненадежными и хрупкими перед лицом изменений JVM.)

Однако,Есть другой (и IMO лучше) подход.

В последних версиях Hotspot (я полагаю, версии 1.6 и новее) вы можете настроить JVM / GC так, чтобы он раньше сдавался и выбрасывал OOME.В частности, JVM может быть сконфигурирована для проверки того, что:

  • отношение свободной кучи к общей куче больше, чем заданный порог после полного GC, и / или
  • временипотраченное на выполнение ГХ меньше определенного процента от общего.

Соответствующими параметрами JVM являются «UseGCOverheadLimit», «GCTimeLimit» и «GCHeapFreeLimit».К сожалению, параметры настройки Hotspot плохо документированы в общедоступной сети, но все они перечислены здесь .

Предполагая, что вы хотите, чтобы ваше приложение делало разумные вещи ... откажитеськогда у него недостаточно памяти для правильной работы ... тогда просто запустите JVM с меньшим значением "GCTimeLimitor" или "GCHeapFreeLimit", чем значения по умолчанию.

EDIT

Я обнаружил, что MemoryPoolMXBean API позволяет вам посмотреть пиковое использование отдельных пулов памяти (куч) и установить пороговые значения.Однако я никогда не пробовал этого, и у API есть много советов, которые предполагают, что не все JVM реализуют полный API.Итак, я бы по-прежнему рекомендовал подход к настройке HotSpot (см. Выше).

2 голосов
/ 25 ноября 2010

Вы можете использовать getHeapMemoryUsage .

1 голос
/ 25 ноября 2010

Что вы могли бы сделать, это создать поток, который периодически просыпается, вычисляет объем используемой памяти и записывает результат.Затем вы можете выполнить регрессионный анализ результата, чтобы оценить скорость роста памяти в вашем приложении.Если вы знаете скорость роста и максимальный объем памяти, вы можете предсказать (с некоторой уверенностью), когда вашему приложению не хватит памяти.

1 голос
/ 25 ноября 2010

Я вижу два вектора атаки.

Либо контролировать потребление памяти.

Когда вы более или менее постоянно используете много доступной памяти, очень вероятно, что у вас утечка памяти (или просто используете слишком много памяти).VM будет постоянно пытаться освободить часть памяти без особого успеха => постоянное высокое использование памяти.

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

Другой вектор атаки - отслеживать, как часто и какого родауспех gc работает.Если он часто запускается с небольшим приростом памяти, скорее всего, у вас проблема.

Я не знаю, можете ли вы получить доступ к такого рода информации непосредственно из вашей программы.Но если ничего другого, я думаю, вы можете указать параметры при запуске, которые превращают информацию журнала gc в файл, который, в свою очередь, может быть проанализирован.

0 голосов
/ 05 декабря 2013

Я использовал plumbr для обнаружения утечек памяти, и это был отличный опыт, хотя лицензия очень дорогая: http://plumbr.eu/

0 голосов
/ 25 ноября 2010

Я думаю, что JVM делает именно это для вас и выдает java.lang.OutOfMemoryError: GC overhead limit exceeded. Так что если вы перехватываете OutOfMemoryError и проверяете это сообщение, то у вас есть то, что вы хотите, не так ли?

См. этот вопрос для более подробной информации

0 голосов
/ 25 ноября 2010

Вы можете передавать аргументы вашей виртуальной машине Java, которая предоставляет вам диагностику GC, например

  1. -verbose:gc Этот флаг включает регистрацию информации GC.Доступно во всех JVM.

  2. - XX:+PrintGCTimeStamps Печатает время, когда GC происходят относительно начала приложения.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...