Поиск утечек памяти (memory leaks) в Tomcat 5
Поиск утечек памяти (memory leaks) в Tomcat 5
Пришлось разбираться комплексно со всей системой.
Обновление Mod_jk никакой пользы не принесло, экзмепляры продолжали зависать. Чтобы исключить теоретические проблемы с mod_jk
mod_jk был заменён на mod_proxy с прямым обращением к серверному http коннектору.
В httpd.conf вместо JkMount использована директива ProxyPass:
ProxyPass /prov/ http://127.0.0.1:8580/prov/
ProxyPassReverse /prov/ http://127.0.0.1:8580/prov/
В tomcat/conf/server.xml доработаны коннекторы для http:
<Connector port="8580" maxHttpHeaderSize="8192"
maxThreads="200" minSpareThreads="4" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
maxPostSize="20971520"
connectionTimeout="10000" disableUploadTimeout="false" maxKeepAliveRequests="30"
/>
http://www.tomcatprobe.org/ . Основные показатели сервера выводятся замечательно.
С его помощью можно определить проблемы:
- С зависшими коннекторами - если вдруг они не отпускаются по нескольку часов.
- С утечками памяти. На графиках видно что происходит с памятью. Если график с течением времени не усредняется на одном уровне - значит есть проблемные приложения.
Для качественной диагностики желательно скачать и установить последнюю версию JDK 1.6. http://java.sun.com/javase/downloads/index.jsp
Чтобы иметь возможность диагностировать состояние памяти, в catalina.sh необходимо прописать ключ -Dcom.sun.management.jmxremote.
Ниже пример настройки для боевого сервера с Jboss:
JAVA_OPTS="-server -XX:MaxPermSize=64m -Dfile.encoding=Cp1251 -Djava.awt.headless=true -Djava.naming.factory.initial=org.jnp.interfaces.NamingContextFactory -Djava.naming.provider.url=jnp://127.0.0.1:1199 -Djava.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces -Dconfigure_logging=true -Xms64m -Xmx768m -Dcom.sun.management.jmxremote"
3.Диагностика утечек памяти. После наблюдения за сервером через tomcatprobe стало очевидным что какое-то приложение поглащает память и не желает её отпускать.
Для начала был создан новый экземпляр tomcat на который перенаправлена работа с новыми приложениями. Разделение старых приложений и новых позволило независимо мониторить два экземпляра tomcat и выявить проблемное приложение.
Для диагностики утечек в JDK 6 появилось множество чудеснейших утилит:
- jmap. Позволяет увидеть состояние памяти и сделать дамп загруженных объектов и их ссылок.
- jhat. Отличная утилита, которая работает с дампом и позволяет через удобный http интерфейс его просмотреть.
Для начала необходимо выяснить какой pid у вашего приложения (далее речь идёт о linux). С этой задачей легко справляется команда jps - она демонстрирует pid всех запущенных java-приложений.
Выбираем необходимый нам пид и создаём дамп:
jmap -dump:format=b,file=/tmp/13517.dmp 13517
После этого запускаем сервер jhat:
jhat /tmp/13517.dmp
Теперь мы имеем всю информацию о загруженных классах по адресу:
http://servername:7000/
Смотрим какой класс больше всех создан:
iexplore http://servername:7000/showInstanceCounts/
вероятнее всего именно он держит память приложения. Щёлкнув по названию класса получаем подробнейшее описание кто и как держит этот объект.
Следующей точкой утечки оказалась старая библиотека ehcache. И последней каплей, забивавшей память, оказалась настройка в ehcache.xml указывавшая на хранение кэша некоторых объектов в течение 24 часов.
В результате все проблемные библиотеки были заменены на более свежие стабильные версии.
Утилита подойдёт любителям графических интерфейсов. Очень наглядно представлены все графики и разбор дампов.
На этом танцы с дампами прекратились, до новых времён, до следующих ошибок :)
Вводная
На боевом сервере неожиданно начались проблемы с памятью, дольше часа экземпляр томката не выдерживал и глухо зависал.Пришлось разбираться комплексно со всей системой.
Срочные меры
1. Самое обидное, что модуль mod_jk метил экземпляр томката как нерабочий, переходил к другому экземпляру и весил его тоже.Обновление Mod_jk никакой пользы не принесло, экзмепляры продолжали зависать. Чтобы исключить теоретические проблемы с mod_jk
mod_jk был заменён на mod_proxy с прямым обращением к серверному http коннектору.
В httpd.conf вместо JkMount использована директива ProxyPass:
ProxyPass /prov/ http://127.0.0.1:8580/prov/
ProxyPassReverse /prov/ http://127.0.0.1:8580/prov/
В tomcat/conf/server.xml доработаны коннекторы для http:
<Connector port="8580" maxHttpHeaderSize="8192"
maxThreads="200" minSpareThreads="4" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
maxPostSize="20971520"
connectionTimeout="10000" disableUploadTimeout="false" maxKeepAliveRequests="30"
/>
Поиск утечек
2.Далее началась возня только с tomcat. Для диагностики состояния сервера рекомендую использовать веб-приложение TomcatProbe.http://www.tomcatprobe.org/ . Основные показатели сервера выводятся замечательно.
С его помощью можно определить проблемы:
- С зависшими коннекторами - если вдруг они не отпускаются по нескольку часов.
- С утечками памяти. На графиках видно что происходит с памятью. Если график с течением времени не усредняется на одном уровне - значит есть проблемные приложения.
Для качественной диагностики желательно скачать и установить последнюю версию JDK 1.6. http://java.sun.com/javase/downloads/index.jsp
Чтобы иметь возможность диагностировать состояние памяти, в catalina.sh необходимо прописать ключ -Dcom.sun.management.jmxremote.
Ниже пример настройки для боевого сервера с Jboss:
JAVA_OPTS="-server -XX:MaxPermSize=64m -Dfile.encoding=Cp1251 -Djava.awt.headless=true -Djava.naming.factory.initial=org.jnp.interfaces.NamingContextFactory -Djava.naming.provider.url=jnp://127.0.0.1:1199 -Djava.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces -Dconfigure_logging=true -Xms64m -Xmx768m -Dcom.sun.management.jmxremote"
3.Диагностика утечек памяти. После наблюдения за сервером через tomcatprobe стало очевидным что какое-то приложение поглащает память и не желает её отпускать.
Для начала был создан новый экземпляр tomcat на который перенаправлена работа с новыми приложениями. Разделение старых приложений и новых позволило независимо мониторить два экземпляра tomcat и выявить проблемное приложение.
Для диагностики утечек в JDK 6 появилось множество чудеснейших утилит:
- jmap. Позволяет увидеть состояние памяти и сделать дамп загруженных объектов и их ссылок.
- jhat. Отличная утилита, которая работает с дампом и позволяет через удобный http интерфейс его просмотреть.
Для начала необходимо выяснить какой pid у вашего приложения (далее речь идёт о linux). С этой задачей легко справляется команда jps - она демонстрирует pid всех запущенных java-приложений.
Выбираем необходимый нам пид и создаём дамп:
jmap -dump:format=b,file=/tmp/13517.dmp 13517
После этого запускаем сервер jhat:
jhat /tmp/13517.dmp
Теперь мы имеем всю информацию о загруженных классах по адресу:
http://servername:7000/
Смотрим какой класс больше всех создан:
iexplore http://servername:7000/showInstanceCounts/
вероятнее всего именно он держит память приложения. Щёлкнув по названию класса получаем подробнейшее описание кто и как держит этот объект.
Выводы
4. Шаманства с дампами памяти позволили выявить проблемные библиотеки - hibernate 3 содержал ошибку связанную с неправильным использованием cglib.Следующей точкой утечки оказалась старая библиотека ehcache. И последней каплей, забивавшей память, оказалась настройка в ehcache.xml указывавшая на хранение кэша некоторых объектов в течение 24 часов.
В результате все проблемные библиотеки были заменены на более свежие стабильные версии.
К сведению
5. Ещё одна удобная утилита, которая более уместна при локальной разработке или при возможности доступа к серверу через vnc (или X server) - https://visualvm.dev.java.net/.Утилита подойдёт любителям графических интерфейсов. Очень наглядно представлены все графики и разбор дампов.
На этом танцы с дампами прекратились, до новых времён, до следующих ошибок :)