JMX:如何防止 servlet 容器中的类加载器内存泄漏?
我想知道是否或如何处理从部署在 servlet 容器上的应用程序直接或间接注册的 MBean。
在大多数情况下,有两个选项可以检索 MBeanServer
,您可以使用它们来注册
使用
MBeanServerFactory.createMBeanServer()
创建自己的MBeanServer
>使用
ManagementFactory.getPlatformMBeanServer()
使用第一个选项时,可以轻松取消注册所有 MBean: 只需调用 MBeanServer.releaseMBeanServer(myMBeanServer)
。
但是许多第三方应用程序中经常使用的第二个选项又如何呢? (顺便说一句,这也是 Sun/Oracle 推荐的方式)。
由于使用了 MBeanServer
平台,因此当 servlet 上下文被销毁时,它不会被取消注册 - 但更糟糕的是,它仍然保留对 Web 应用程序类加载器的引用。
因此Web 应用程序的所有静态引用都不会被释放,这会导致泄漏。
如果您想测试一下:只需部署一个简单的 Web 应用程序,该应用程序分配一个 100MB 的数组,该数组是静态引用并使用 oracle jdbc司机(它将使用平台 mbean 服务器注册一个诊断 MBean),部署在 tomcat 上。停止应用程序并重新启动 - 重复此操作,您将遇到 OutOfMemoryError
。
问题:
我是否必须处理这些一般问题,还是 servlet 容器和/或第 3 方库的问题?
有没有办法获取
MBeanServer
的所有 MBean,这些 MBean 是由特定ClassLoader
加载的?我可以采取什么措施来防止这种情况发生?我是否必须跟踪所有注册到平台
MBeanServer
的 MBean 并在contextDestroyed()
期间取消注册?
I am wondering if or how I should deal with MBeans which are registered directly or indirectly from my application which gets deployed on a servlet container.
In most cases there are two options to retrieve a MBeanServer
which you can use for registering
create your own
MBeanServer
usingMBeanServerFactory.createMBeanServer()
Use
ManagementFactory.getPlatformMBeanServer()
When using the first option, it's easy to deregister all MBeans:
Just invoke MBeanServer.releaseMBeanServer(myMBeanServer)
.
But what about the second option which is used often in many 3rd party applications?
(and BTW, this is also the recommended way from Sun/Oracle).
Because the platform MBeanServer
is used, it won't be deregistered when the servlet context is destroyed - but even worse it still helds a reference to the web application classloader.
As a consequence all static references of the web application won't get released which results in a leak.
If you like to test this: Just deploy a simple web application which allocates a 100MB array which is references statically and which uses an oracle jdbc driver (it will register a diagnostic MBean using the platform mbean server), deployed on tomcat. Stop the application and restart it - repeat this, and you'll hit an OutOfMemoryError
.
Questions:
Do I have to deal with these issues in general or is it a problem of the servlet container and/or the 3rd party library?
Is there a way to get all MBeans of an
MBeanServer
which classes are loaded by a specificClassLoader
?What can I do to prevent this? Do I have to keep track of all registered MBeans to the platform
MBeanServer
and unregister it duringcontextDestroyed()
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我正在使用如此邪恶的第三方。为了确保正确关闭 servlet 上下文,我使用
mbeanServer.queryMBeans(null, null)
枚举 bean,然后使用unregisterMBean()
枚举位于第三个域中的 bean派对。I'm using such an evil third-party. To ensure proper servlet context shutdown, I enumerate the beans using
mbeanServer.queryMBeans(null, null)
and thenunregisterMBean()
the beans which are in the domain of the third-party.这是我的标准建议。我不知道有更好的选择。
This has been my standard advice. I'm not aware of a better option.
bkail 在说什么。此外,如果您使用 Spring 等框架(请参阅 MBeanExporter),它应该在 Context 关闭时负责取消注册 JMX 对象,这应该作为重新部署 Web 应用程序的一部分进行。
What bkail is saying. Also if you're using framework such as Spring (see MBeanExporter) it should take care of unregistering your JMX objects upon Context shutdown, which should happen as part of redeploy of the webapp.
同时你可以获取所有的Mbean,并检查它是否被容器类加载器加载,然后注销它。
示例代码是:
我建议您阅读以下项目 classloader-leak-prevention github。
该项目有一系列方法来处理容器中的类加载器泄漏。
对于这个问题,你可以看到 MBeanCleanUp.java
while you can get all the Mbeans,and check if it was loadered by the container classloader,and then unregist it.
the Sample code is:
I recommend you to read the project classloader-leak-prevention from github.
the project have a series of method to deal with classloader leak from containers.
for this question,you can see the MBeanCleanUp.java