Tomcat与内存泄露处理

似乎从 Java 入门的时候,就有这样的说法来考查 Java开发者:

Java 不像 C++ 那样自己管理内存,有Java 虚拟机负责进行垃圾回收,再也没有内存泄露的问题了。

但是随着开发经历的增长,已经开发过应用的增多,应用内需要加载的 class 增多,经常就会遇到内存溢出(OOM)。或者更确切的说,因为加载 class 的增多导致的内存溢出是java.lang.OutOfMemoryError: PermGen space

此时,解决OOM的方式一般是

  1. 分析应用的代码写的是否有问题,可以通过一些工具观察应用内占用内存较多的 class 类型 (比如通过 JVisualVM 来分析Java七武器系列多情环 --多功能Profiling工具 JVisual VM,或者通过MAT来分析)

  2. 修改 JVM启动参数,增大关于 Perm Gen 的配置。

在 Tomcat 这一类的 应用服务器中,由于其做为应用的容器运行,可能自身的Perm Gen 占用并不多,但需要考虑部署到容器中的应用占用。有些应用依赖了大量的第三方类库,也有一些应用会在运行时动态生成大量的 class,这些内容的加载,都容易导致 Perm Gen 的 OOM。

对于 OOM 的处理,内部会在启动时占用一小块内存,在 OOM 产生的时候释放掉来临时缓解一下,这种称为oomParachute。前面写过一篇介绍的文章(预防OOM,Tomcat是这样做的)。

除此之外,Tomcat 在 manager 应用中还提供了发现内存泄漏的功能。

图上说明写的明白,该功能主要用于分析在应用停止、重部署、解除部署时是否造成了内存泄漏。 

在请求后,manager的上方信息显示区域会提示当前是否有应用造成的内存泄漏。

但需要注意的是此功能会触发一次 Full GC 的执行,代码中使用的是 System.gc(),在生产环境中如果使用需要谨慎。

那么,在什么情况下会导致所谓的应用内存泄漏呢?

我们都知道, 为了实现应用间的 class 隔离, Tomcat 对于每个应用,都会单独使用一个 WebappClassLoader,这样,多个应用间即使都使用到一个 类库的不同版本,也不会相互影响造成冲突。 (参考前面的文章:Tomcat类加载器以及应用间class隔离与共享类加载器与类冲突)

但是,在这种情况下,当一个应用已经执行了停止操作,或者执行了重部署操作,此时是会生成一个新的 classLoader 来加载新部署的应用类信息。

我们知道,在 Java 中,类与类之间是存在引用关系的,类似于强引用,弱引用,幻影引用,用来在GC时将一些不需要的 class 回收掉,腾出空间。按理说之前的 classLoader 本应该被垃圾回收,但在某些时候,由于一些类之前的引用关系导致该 classLoader,以及其加载的一系列 class 文件, 都不能被标识为垃圾,此时这些 class 依然驻留在 Perm Gen,随着应用多次启停,多次重部署之后,出现了 Perm Gen 的 OOM。

一般以下类库的使用容易导致 class loader 逃过垃圾回收,产生内存泄漏:

  • JDBC driver 注册

  • 一些 logging 框架

  • 没有移除的 ThreadLocal的使用

  • 未停止的 Thread

此外,一些 Java API 的使用也容易导致此问题,例如

  • javax.imageio API

  • XML 解析 

  • RMI 使用

由于这些容易占用 classLoader,导致其不能被回收,如果这些 class 交给各个应用的类加载器进行加载,就会使得 Perm  Gen 中这些类越来越多,从而产生泄漏。

为此,在 Tomcat 中引入了 JreMemoryLeakPreventionListener 这个组件。实现思路是在 Tomcat 启动时,通过 System class Loader 来加载这些类。 由于类加载器的加载原理(默认父优先,而且这些系统的类,都会委托给系统类加载器进行加载),这些类不会再被 WebclassLoader 重新加载,从而减小内存泄漏的产生。

默认在 Tomcat 的配置 server.xml 中已经开启了该组件,所以这些功能你已经不知不觉中在使用。

                              赞赏随意

            

相关阅读

类路径(classpath)的原理及在Tomcat中的使用

类加载器与类冲突

类加载器与类的热替换(Hotswap)

Tomcat类加载器以及应用间class隔离与共享

为什么你的Manager登录不成功?

PS: 对于一些 Tomcat常见问题,在公众号的【常见问题】菜单中,有需要的朋友欢迎关注查看。

觉得本文对你有帮助?请分享给更多人支持一下吧,谢谢

关注『 Tomcat那些事儿  』 ,发现更多精彩文章!了解各种常见问题背后的原理与答案。深入源码,分析细节,内容原创,欢迎关注。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值