记一次 java class loader 引发的严重内存泄露

          本周负责对一个 Web 应用进行故障分析,最终发现应用停止响应故障是由于在特定情况下 java class loader 所引发的严重内存泄露造成的,在此作以记录。


          该 Web 应用故障表现为运行一段时间后,会出现服务停止响应的情况,间隔时间也很随机。在对其 javacore 分析后发现,停止响应的原因在于 jvm heap 耗尽,导致 web container 工作线程抛出了 out of memory 异常。

 

 

 

          进一步对 heap dump 分析发现,应用 jvm 中发生了严重的内存泄露,而且泄露对象数量和占用的内存空间都很多,其根本的原因是由于 jvm class loader 泄露。下面的就是对比两次间隔一段负载后的 heap 变化情况(验证环境):

 

 

          可以看到虽然 compound class loader 数量没有增加,但其引用的对象容量却大大增加了。我们知道在 java 中 class loader 用于加载 Class 定义并为其生成类的实例(Classs 实例),而且所有对象实例会引用其 Class 实例,这样就形成如下引用关系:

 

 

          在 WebSphere、Tomcat 和 JBoss 等 jvm 运行环境中,class loader 是有层次的,每个层次的 class loader 作用和生命周期是不同的,以当前应用系统所部署的 WebSphere 为例,其结构如下:

 

 

 

          其中的“WAS 扩展类装入器”为 com/ibm/ws/bootstrap/ExtClassLoader,“WAS 复合类装入器”为 com/ibm/ws/classloader/CompoundClassLoader 类型。

          回到这里讨论的 Web 应用上,通过应用部署的人员了解到,当前系统在每次更新发布版本应用后,都会有选择的重新启动应用服务器(server),更多的时候为了不影响部署在同一应用服务器上的其它应用,在重新部署应用后不会同时重新启动应用服务器 ,这样一来,由于 jvm 中 class loader 生命周期的不同,就会出现下面描述的情况,而结果就是出现大范围的内存泄露:

 

 

          其根本原因就在于应用级生命周期的 class loader 及期所有加载的类和类的实例对象与服务器级生命周期的 class loader 加载的类的实例存在引用关系,造成重新发布应用而不重新启动应用服务器后,jvm 的泄露所以上一应用所加载、创建的对象实例。 可见这种内存泄露量是巨大的。

          对于这种 jvm class loader 引发的内存泄露,这里有篇文章讨论的非常详细,同时也提出了一些可能的原因和解决方法,这里就不详细说明了,建议参考。

 

关于 Class 类加载器内存泄漏问题的探讨

类装入器查看器设置

 

          说句题外话,这个端午节过得酒气很重,现在才冲回来,头晕,但洒店的网络现在也正常了很多。大家端午节同乐~~

 

// 2009.05.30 0:12 添加

 

          这几篇系列文章很好的介绍了 IBM JDK 垃圾收集及内存管理机制,把这些基础的重要技术细节说明的非常详细,在这里推荐下。另外,可以结合 IBM JVM Diagnostics Guide 来看,对 jvm 层面的性能优化和故障排除很对胃口。

 

IBM JDK 垃圾收集及内存管理机制 - (1)
IBM JDK 垃圾收集及内存管理机制 - (2)
IBM JDK 垃圾收集及内存管理机制 - (3)

 

// 2009.06.06 14:09 添加

 

作者:lzy.je
出处:http://lzy.iteye.com
本文版权归作者所有,只允许以摘要和完整全文两种形式转载,不允许对文字进行裁剪。未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

 

你可能感兴趣的:(Troubleshooting,&,tuning)