JMX: Как предотвратить утечку памяти Classloader в контейнере сервлета?
Мне интересно, как и как я должен иметь дело с MBeans, которые прямо или косвенно регистрируются из моего приложения, которое развертывается в контейнере сервлетов.
В большинстве случаев есть два варианта получения MBeanServer
, которые вы можете использовать для регистрации
При использовании первого варианта легко удалить все MBeans:
Просто вызовите MBeanServer.releaseMBeanServer(myMBeanServer)
.
Но как насчет второго варианта, который часто используется во многих сторонних приложениях?
(и BTW, это также рекомендуется для Sun/Oracle).
Поскольку платформа MBeanServer
используется, она не будет отменена регистрации, если контекст сервлета будет уничтожен, но еще хуже, он все еще содержит ссылку на загрузчик классов веб-приложений.
Как следствие, все статические ссылки веб-приложения не будут выпущены, что приведет к утечке.
Если вам нравится протестировать это: просто разверните простое веб-приложение, которое выделяет массив 100 Мбайт, который является ссылкой статически и который использует драйвер oracle jdbc (он зарегистрирует диагностический MBean с использованием сервера mbean платформы), развернутого на tomcat. Остановите приложение и перезапустите его - повторите это, и вы нажмете OutOfMemoryError
.
Вопросы:
-
Должен ли я иметь дело с этими проблемами вообще или это проблема контейнера сервлетов и/или сторонней библиотеки?
-
Есть ли способ получить все MBeans MBeanServer
, какие классы загружаются определенным ClassLoader
?
-
Что я могу сделать, чтобы предотвратить это? Должен ли я отслеживать все зарегистрированные MBeans на платформе MBeanServer
и отменить регистрацию в течение contextDestroyed()
?
Ответы
Ответ 1
Что я могу сделать, чтобы предотвратить это? У меня есть должны отслеживать все зарегистрированные MBeans для платформы MBeanServer и отменить регистрацию в течение contextDestroyed()?
Это был мой стандартный совет. Я не знаю лучшего варианта.
Ответ 2
Я использую такую злую стороннюю сторону. Чтобы обеспечить правильное выключение контекста сервлета, я перечисляю beans с помощью mbeanServer.queryMBeans(null, null)
, а затем unregisterMBean()
beans, которые находятся в домене стороннего пользователя.
Set<ObjectInstance> beans = mbeanServer.queryMBeans(null, null);
for (ObjectInstance objectInstance : beans) {
if (objectInstance.getObjectName().getDomain().equals("third-party-domain")) {
try {
mbeanServer.unregisterMBean(objectInstance.getObjectName());
} catch (MBeanRegistrationException exception) {
//error handling
} catch (InstanceNotFoundException exception) {
//error handling
}
}
}
Ответ 3
Что говорит баклай. Кроме того, если вы используете фреймворк, такой как Spring (см. MBeanExporter), он должен позаботиться о том, чтобы отменить регистрацию объектов JMX при завершении контекста, что должно произойти как часть повторного развертывания webapp.