Мы запускаем небольшое веб-приложение, написанное на JRuby на Rails и работающее под Tomcat. Мы используем серверную часть Spring, которая используется совместно с другим рабочим веб-приложением. К сожалению, мы продолжаем сталкиваться с проблемами PermGen.
ОС: Ubuntu Linux 2.6.24-24-сервер №1 SMP x86_64 GNU / Linux
Java: 1.6.0_21
Tomcat: 6.0.28
JRuby: 1.5.0
Рельсы: 2.3.7
В настоящее время мы сканируем Google, Yahoo и Baidu, поэтому использование сайта возросло. Я следил за Tomcat с помощью JConsole, и мы определенно видим проблему с чрезмерным количеством классов. Когда запускается tomcat, у нас загружается около 12 000 классов. Через 8 часов у нас загружено почти 75 000 классов. PermGen идет от 100 МБ до 460 МБ одновременно.
Разгрузка классов работает, но она выгружает только ~ 500 классов за тот же 8-часовой период. Кажется, что PermGen никогда не собирают.
Мы работаем со следующими параметрами VM для Tomcat:
-Xms2048m -Xmx2048m -XX:MaxPermSize=512m -XX:PermSize=128m \
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4 \
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
Очевидно, что есть какая-то утечка. Вопрос как где? Любой совет, как отследить, кто и что за это отвечает? Я надеюсь, что это действительно глупая ошибка с нашей стороны, но я не уверен, с чего начать.
Любой совет будет принят с благодарностью.
РЕДАКТИРОВАТЬ
Похоже, мы видим один новый класс, созданный для каждого входящего запроса.
РЕДАКТИРОВАТЬ 2
Это определенно связано с JRuby. Используя JConsole, я включил режим Verbose для загрузчика классов. Вот пример из catalina.out:
[Loaded anon_class1275113147_895127379 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar]
[Loaded anon_class1354333392_895127376 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar]
[Loaded anon_class1402528430_895127373 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar]
Таким образом, возникает вопрос, как мне отследить группу, ответственную за создание этих дополнительных классов?
РЕДАКТИРОВАТЬ 3
Не уверен, что это проблема, но каким-то образом мы получаем безумное количество загрузчиков классов. Побежал jmap -permstat PID
и получил:
class_loader classes bytes parent_loader alive? type
total = 1320 135748 947431296 N/A alive=1, dead=1319 N/A
Это кажется немного чрезмерным. Большинство из них являются одним из трех типов загрузчиков классов: sun.reflect.DelegatingClassLoader
, org.jruby.util.JRubyClassLoader
или org.jruby.util.ClassCache$OneShotClassLoader
. Опять же, пример вывода из jmap -permstat
:
class_loader classes bytes parent_loader alive? type
0x00007f71f4e93d58 1 3128 0x00007f71f4d54680 dead sun/reflect/DelegatingClassLoader@0x00007f72ef9a6dc0
0x00007f721e51e2a0 57103 316038936 0x00007f720431c958 dead org/jruby/util/JRubyClassLoader@0x00007f72f2fd1158
0x00007f72182f2b10 4 12944 0x00007f721d7f3030 dead org/jruby/util/JRubyClassLoader@0x00007f72f2fd1158
0x00007f721d7d50d8 9 457520 0x00007f720431c958 dead org/jruby/util/ClassCache$OneShotClassLoader@0x00007f72f3ce2368