JMX: Как предотвратить утечки памяти Classloader в контейнере сервлета? - PullRequest
10 голосов
/ 20 июня 2011

Мне интересно, следует ли мне обращаться с MBean-компонентами, которые прямо или косвенно зарегистрированы в моем приложении, развернутом в контейнере сервлета.

В большинстве случаев есть два варианта получения MBeanServerкоторый вы можете использовать для регистрации

  • создать свой собственный MBeanServer, используя MBeanServerFactory.createMBeanServer()

  • Использовать ManagementFactory.getPlatformMBeanServer()

При использовании первого варианта легко отменить регистрацию всех MBean: просто вызовите MBeanServer.releaseMBeanServer(myMBeanServer).

Но как насчет второго варианта, который часто используется во многих сторонних приложениях?(и кстати, это также рекомендуемый путь от Sun / Oracle).

Поскольку используется платформа MBeanServer, она не будет отменена при уничтожении контекста сервлета, но, что еще хуже, она все еще удерживается.ссылка на загрузчик классов веб-приложения.
Как следствие, все статические ссылки веб-приложения не будут освобождены, что приведет к утечке.

Если вы хотите проверить этоПросто разверните простое веб-приложение, которое выделяет массив размером 100 МБ, который является статической ссылкой и использует драйвер oracle jdbc (он регистрирует диагностический MBean с использованием сервера платформы mbean), развернутого на tomcat.Остановите приложение и перезапустите его - повторите это, и вы получите OutOfMemoryError.

Вопросы:

  • Нужно ли мнерешать эти проблемы в целом или это проблема контейнера сервлета и / или сторонней библиотеки?

  • Есть ли способ получить все MBean MBeanServer, какие классызагружаются определенным ClassLoader?

  • Что я могу сделать, чтобы предотвратить это?Нужно ли отслеживать все зарегистрированные MBeans на платформе MBeanServer и отменять регистрацию во время contextDestroyed()?

Ответы [ 4 ]

3 голосов
/ 16 мая 2013

Я пользуюсь таким злым сторонним. Чтобы обеспечить правильное отключение контекста сервлета, я перечисляю bean-компоненты, используя mbeanServer.queryMBeans(null, null), а затем unregisterMBean() bean-компоненты, которые находятся в домене стороннего производителя.

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
        }
    }
}
1 голос
/ 20 июня 2011

Что я могу сделать, чтобы предотвратить это?Нужно ли отслеживать все зарегистрированные MBean-компоненты на платформе MBeanServer и отменять регистрацию во время contextDestroyed ()?

Это был мой стандартный совет.Я не знаю лучшего варианта.

0 голосов
/ 05 ноября 2018

пока вы можете получить все Mbeans и проверить, был ли он загружен загрузчиком классов контейнера, а затем отменить его регистрацию. Пример кода:

final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
final Set<ObjectName> allMBeanNames = mBeanServer.queryNames(new ObjectName("*:*"), null);
for(ObjectName objectName : allMBeanNames) {
  final ClassLoader mBeanClassLoader = mBeanServer.getClassLoaderFor(objectName);
  if(containnerClasssloader.isClassLoaderOrChild(mBeanClassLoader)) { // MBean loaded by containnerClasssloader  
        mBeanServer.unregisterMBean(objectName);
 }
}

Рекомендую прочитать проект classloader-предотвращение утечек от github. В проекте есть ряд методов для устранения утечек из загрузчиков классов из контейнеров. по этому вопросу вы можете увидеть MBeanCleanUp.java

0 голосов
/ 21 июня 2011

Что говорит Бкаил.Также, если вы используете фреймворк, такой как Spring (см. MBeanExporter), он должен позаботиться об отмене регистрации ваших объектов JMX при закрытии контекста, что должно произойти как часть повторного развертывания веб-приложения.

...