Мы запускаем маленькое веб-приложение записанный JRuby на направляющих, работающих под Tomcat. Мы используем бэкенд Spring, это совместно используется с другим производственным веб-приложением. К сожалению, мы продолжаем сталкиваться с проблемами PermGen.
ОС: Ubuntu Linux 2.6.24 24 сервера № 1 Java SMP x86_64 GNU/Linux: 1.6.0_21 Tomcat: 6.0.28 JRuby: 1.5.0 направляющих: 2.3.7
Мы в настоящее время становимся проверенными Google, Yahoo и Baidu, таким образом, использование сайта закончилось. Я контролировал Tomcat с JConsole, и мы определенно видим проблему с чрезмерным количеством классов. Когда кот запускается, у нас есть приблизительно 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
Это кажется немного чрезмерным. Большинство является одним из трех видов classloaders: 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
PermGen определенно является проблемой для приложений на основе JRuby. Я не удивлен, что CMS мало что собирает. Как правило, это не настоящая утечка памяти, а просто приложение сильно нагружает пермген и еще не выровнялось.
Я могу предложить несколько вариантов:
threadsafe!
режим. Выполнение приложения в одном режиме - еще один способ получить большую экономию памяти, и это также относится к permgen. EDIT: К вашему сведению, этот вопрос оказался ошибкой JRuby. Релизы 1.5.2 и 1.6 должны исправить эту проблему. В целом, мои комментарии выше остаются в силе.
Есть инструменты профилирования, и люди, которые знают, как их использовать. Боюсь, я не один из них.
Совет по перебору:
Перезапускайте ваш Tomcat каждые 8 часов. Общее время простоя по мнению ваших пользователей будет очень приемлемым. Проблема решена ;)
EDIT
О, хорошо! Скучное решение.