Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Как устранить утечку памяти?


Автор: Barvetal 24.10.2007, 23:10
Всем здравствуйте!

Периодически падает jvm по причине OutOfMemoryError.

Как мне отловить утечку памяти?

Для того, чобы понять, где утечка, я включил опции -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/jmap. Версия jvm - 6.02. Версия ОС: SuSe Linux 10.2.

Но при падении по причине нехватки памяти дамп памяти не создается.

Запись в логе:
Код

SEVERE: Caught exception (java.lang.OutOfMemoryError: unable to create new native thread) executing org.apache.tomcat.util.net.LeaderFollowerWorkerThread@1236
1e3, terminating thread
а затем:
Код

# java.lang.OutOfMemoryError: requested 2048000 bytes for GrET in /BUILD_AREA/jdk6_02/hotspot/src/share/vm/utilities/growableArray.cpp. Out of swap space?
#
#  Internal Error (414C4C4F434154494F4E0E494E4C494E450E4850500017), pid=15746, tid=601537440
#
# Java VM: Java HotSpot(TM) Server VM (1.6.0_02-b05 mixed mode)
# An error report file with more information is saved as hs_err_pid15746.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#


В данном случае он написал две записи об OutOfMemoryError. Но как правило пишет только одну запись - вторую.

По пути /opt свободно 6Гб. Под java машину я выделил 3Гб (-Xmx3g). То-есть, дамп памяти вряд ли не создался по причине нехватки места на диске.

И еще один момент. Через какое-то время после падения сервера я ищу jvm-процес командой 
ps -ef | grep java, но java-машины он не находит. То-есть, падение такое, что даже jvm-процесс в Linux убивается...

Еще интерестный момент. Когда я смотрю гистрограмму памяти (jmap -histo:live <pid>), то jvm обычно потребляет 1.2-1.8 Гб памяти (из максимальных 3 Гб). Так вот, примерно в 19:10 jvm потребляла 1.2Гб, а в 19:45 того же дня вся память закончилась... Перед этим сайт простоял 3 суток, и проработал в режиме "каждые 40 минут освобождал память до 1-2Гб, а потом медленно накапливал до 3 Гб). А в этот раз память он просто не освободил. 

Таким образом, насколько я понимаю, память в принципе не накапливается постепенно. Похоже, что либо она накапливается в течение 45 минут, либо просто почему-то не освобождается...

Скриншоты приложены. Первый скриншот - jconsole, второй - jmeter.

Скажите, как можно устранить эту утечку памяти? Потому что у меня уже просто нет вариантов :(

Скриншот: user posted image

Автор: COVD 24.10.2007, 23:39
Цитата

Таким образом, насколько я понимаю, память в принципе не накапливается постепенно

т.е. это не "утечка" в традиционном смысле. Это похоже на ошибку в коде, когда вдруг очень быстро захватывается вся имеющаяся память. Например, сервер постоянно обращается к внешнему ресурсу, а ресурс вдруг перестает отвечать и  все запросы выстраиваются в очередь -> очередь растет пока не кончится память. 

Автор: Barvetal 25.10.2007, 10:34
Цитата(COVD @ 24.10.2007,  23:39)
Цитата

Таким образом, насколько я понимаю, память в принципе не накапливается постепенно

т.е. это не "утечка" в традиционном смысле. Это похоже на ошибку в коде, когда вдруг очень быстро захватывается вся имеющаяся память. Например, сервер постоянно обращается к внешнему ресурсу, а ресурс вдруг перестает отвечать и  все запросы выстраиваются в очередь -> очередь растет пока не кончится память.

Цитата

Например, сервер постоянно обращается к внешнему ресурсу, а ресурс вдруг перестает отвечать и  все запросы выстраиваются в очередь

Похоже. Но обратите внимание на график потоков. Они на нуле. Если бы было так, как вы говорите, потоки бы выросли.

И еще один момент. Обратите, пожалуйста, внимание на графики памяти, которые я приложил. Как здесь видно, GC для OldGen срабатывает примерно раз в 45 минут успешно (каждые 45 минут видно, как количество потребляемой памяти падает до 1-2Гб), и в каждые эти 45-минутные интервалы потребляемая память плавно растет. А тут вдруг в этот раз GC для OldGen'а рас - и не освободил ничего!

Вот у меня и возникает вопрос - как это может быть? Может, произошел какой-то сбой в jvm, и она не запустила GC для OldGen? Или как тогда может быть, что за тот же временной интервал вся память, накопленная за 45 минут, стала неосвобождаемой?

Пожалуйста, проанализируйте график!

Автор: COVD 25.10.2007, 15:52
Цитата

Похоже. Но обратите внимание на график потоков. Они на нуле. Если бы было так, как вы говорите, потоки бы выросли.


Наверное, график отображает нормальный режим, когда поток быстро делает свое дело и уходит. А лавинообразное нарастание потоков просто не вошло в график. Или это не потоки сьели память. Надо знать приложение. 

Цитата

И еще один момент. Обратите, пожалуйста, внимание на графики памяти, которые я приложил. Как здесь видно, GC для OldGen срабатывает примерно раз в 45 минут успешно (каждые 45 минут видно, как количество потребляемой памяти падает до 1-2Гб), и в каждые эти 45-минутные интервалы потребляемая память плавно растет. А тут вдруг в этот раз GC для OldGen'а рас - и не освободил ничего!


Это нормальные графики. А не освободил ничего возможно потому что не смог. Если новые обьекты стремительно создаются и не отпускаются, то GC ничего не может сделать. Посмотрите лог GC. Для этого  можно использовать например -Xloggc: и будет в консоль выводиться. По крайней мере увидите, были ли попытки чистить память. На графике это трудно разглядеть. 

Цитата

Вот у меня и возникает вопрос - как это может быть? Может, произошел какой-то сбой в jvm, и она не запустила GC для OldGen? Или как тогда может быть, что за тот же временной интервал вся память, накопленная за 45 минут, стала неосвобождаемой?


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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)