Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JMX:如何防止servlet容器中的类加载器内存泄漏?_Java_Servlets_Memory Leaks_Classloader_Jmx - Fatal编程技术网

Java JMX:如何防止servlet容器中的类加载器内存泄漏?

Java JMX:如何防止servlet容器中的类加载器内存泄漏?,java,servlets,memory-leaks,classloader,jmx,Java,Servlets,Memory Leaks,Classloader,Jmx,我想知道是否应该或如何处理直接或间接从部署在servlet容器上的应用程序注册的MBean 在大多数情况下,有两个选项可用于检索可用于注册的MBeanServer 使用MBeanServerFactory.createMBeanServer() 使用ManagementFactory.getPlatformMBeanServer() 使用第一个选项时,可以轻松取消所有MBean的注册: 只需调用MBeanServer.releaseMeanServer(myMBeanServer) 但是,第

我想知道是否应该或如何处理直接或间接从部署在servlet容器上的应用程序注册的MBean

在大多数情况下,有两个选项可用于检索可用于注册的
MBeanServer

  • 使用
    MBeanServerFactory.createMBeanServer()

  • 使用
    ManagementFactory.getPlatformMBeanServer()

使用第一个选项时,可以轻松取消所有MBean的注册: 只需调用
MBeanServer.releaseMeanServer(myMBeanServer)

但是,第二个选项在许多第三方应用程序中经常使用,这又如何呢? (顺便说一句,这也是Sun/Oracle推荐的方法)

因为使用了平台
MBeanServer
,所以当servlet上下文被破坏时,它不会被取消注册-但更糟糕的是,它仍然会保存对web应用程序类加载器的引用。
因此,不会释放web应用程序的所有静态引用,从而导致泄漏。

如果您想测试这一点:只需部署一个简单的web应用程序,该应用程序分配一个静态引用的100MB数组,并使用一个oracle jdbc驱动程序(它将使用平台MBean服务器注册一个诊断MBean),部署在tomcat上。停止应用程序并重新启动它-重复此操作,您将遇到
OutOfMemoryError

问题:

  • 我是否必须处理这些问题,还是servlet容器和/或第三方库的问题

  • 有没有一种方法可以获取
    MBeanServer的所有MBean
    哪些类是由特定的
    类加载器加载的

  • 我能做些什么来防止这种情况?我是否必须跟踪所有注册到平台
    MBeanServer
    的MBean,并在
    contextdestromed()
    期间注销它

我能做些什么来防止这种情况?是吗 必须跟踪所有已注册的 MBeans到平台MBeanServer和 在注册期间注销它 contextdestromed()


这是我的标准建议。我不知道还有更好的选择。

bkail在说什么。另外,如果您使用的是Spring之类的框架(请参阅MBeanExporter),它应该在上下文关闭时注销JMX对象,这应该作为重新部署webapp的一部分来完成。

我使用的是这样一个邪恶的第三方。为了确保正确关闭servlet上下文,我使用
mbeanServer.queryMBeans(null,null)
枚举bean,然后
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
        }
    }
}
Set bean=mbeanServer.queryMBeans(null,null);
for(ObjectInstance ObjectInstance:beans){
if(objectInstance.getObjectName().getDomain().equals(“第三方域”)){
试一试{
mbeanServer.unregisterMBean(objectInstance.getObjectName());
}捕获(MBeanRegistrationException异常){
//错误处理
}捕获(InstanceNotFoundException异常){
//错误处理
}
}
}

而您可以获取所有MBean,并检查它是否由容器类加载器加载,然后注销它。 示例代码是:

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);
 }
}
final MBeanServer MBeanServer=ManagementFactory.getPlatformMBeanServer();
最终设置allMBeanNames=mBeanServer.queryNames(新对象名(“*:*”),null);
for(ObjectName ObjectName:allMBeanNames){
最终类加载器mBeanClassLoader=mBeanServer.getClassLoaderFor(objectName);
if(containerClasssLoader.isClassLoaderArchild(mBeanClassLoader)){//MBean由containerClasssLoader加载
mBeanServer.unregisterMBean(objectName);
}
}
我建议您阅读github的项目。 该项目有一系列方法来处理容器中的类加载器泄漏。
对于这个问题,您可以看到

“我也只注销web应用程序的类加载器加载的MBean:
如果(mbeanServer.GetClassLoader for(objectInstance.getObjectName()==Thread.currentThread().getContextClassLoader())
虽然此链接可以回答问题,但最好在此处包含答案的基本部分,并提供链接供参考。如果链接页面发生更改,仅链接的答案可能会无效。-因为我不是作者。我认为发布内容不是一个好主意。不过,有一个选项供评论者选择,
链接打开stackoverflow将删除所有答案,因此建议您在帖子中添加一些必要的内容,不需要全部代码。正如网站所说,如果链接页面发生更改,只有链接答案可能无效。我认为网站只是想让答案对所有读者都有用,而不依赖其他网站。好的,我修改了答案,添加了主代码来解释解决问题的方法。