博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Tomcat如何检测内存泄漏
阅读量:6278 次
发布时间:2019-06-22

本文共 2113 字,大约阅读时间需要 7 分钟。


一般情况下,如果我们重启web应用是通过重启tomcat的话,则不存在内存泄漏问题。但如果不重启tomcat而对web应用进行重加载则可能会导致内存泄漏,因为重加载后有可能会导致原来的某些内存无法让GC回收,例如web应用使用了JDBC,驱动会进行注册,当web应用停止时没有反注册就会导致内存泄漏。

看看是什么原因导致tomcat内存泄漏的。这个要从热部署开始说起,因为tomcat提供了不必重启容器而只需重启web应用以达到热部署的功能,其实现是通过定义一个WebappClassLoader类加载器,当热部署时就将原来的类加载器废弃并重新实例化一个WebappClassLoader类加载器。但这种方式可能存在内存泄漏问题,因为ClassLoader是一个结构复杂的对象,导致它不能被GC回收的可能性比较多,除了对ClassLoader对象有引用可能导致其无法回收,还可能对其加载的元数据(方法、类、字段等)有引用都会导致无法被GC回收。

内存泄漏

如上图,tomcat的资源由不同类加载器加载,这里只看BootstrapClassLoader和WebappClassLoader两个类加载器,BootstrapClassLoader负责加载rt.jar包的java.sql.DriverManager,WebappClassLoader负责加载web应用中的mysql驱动包,其中有一个很重要的步骤是mysql的驱动类需要注册到DriverManager中,即DriverManager.registerDriver(new Driver()),它由mysql驱动包自动完成。这样一来当web应用进行热部署操作时,没有将mysql的Driver从DriverManager中反注册掉的话,则会导致整个WebappClassLoader回收不了,造成内存泄漏。

接着看tomcat如何对此内存泄漏进行监控的,要判断WebappClassLoader会不会导致内存泄漏只需判断WebappClassLoader有没有被GC回收即可。在Java中有一种引用叫弱引用,它能很好判断WebappClassLoader有没有被GC回收,被弱引用关联的对象只能生存到下一次垃圾回收发生之前,即如果某WebappClassLoader对象只被某弱引用关联,则它会在下次垃圾回收时被回收,但如果WebappClassLoader对象除了被弱引用关联外还被其他对象强引用,那么WebappClassLoader对象是不会被回收的,根据这些条件就可以判断是否有WebappClassLoader内存泄漏了。

Tomcat的实现是通过WeakHashMap来实现弱引用的,只需将WebappClassLoader对象put到WeakHashMap中,例如weakMap.put(“a”,webappClassLoader),当webappClassLoader及其包含的元素没有被其它任何类加载器中的元素引用到时,JVM发生垃圾回收时则会把webappClassLoader对象回收。

简单的实现代码大致如下:

public class MemoryLeakTest{private Map
childClassLoaders = new WeakHashMap
();public String[] findReloadedContextMemoryLeaks() { System.gc(); List
result = new ArrayList
(); for (Map.Entry
entry : childClassLoaders.entrySet()) { ClassLoader cl = entry.getKey(); if (!((WebappClassLoader) cl).isStarted()) { result.add(entry.getValue()); } } return result.toArray(new String[result.size()]); }}

使用一个WeakHashMap用于跟踪WebappClassLoader,在查找内存泄漏之前会先强制调用System.gc();进行一次垃圾回收,保证没问题的WebappClassLoader都被回收掉,这时如果还有WebappClassLoader的状态是非started(正常启动的都为started,关闭了的则为非started)的,则是未被垃圾回收的WebappClassLoader,属于内存泄漏的。

点击订购作者《Tomcat内核设计剖析》

你可能感兴趣的文章
iOS 多线程总结
查看>>
webpack是如何实现前端模块化的
查看>>
TCP的三次握手四次挥手
查看>>
关于redis的几件小事(六)redis的持久化
查看>>
package.json
查看>>
webpack4+babel7+eslint+editorconfig+react-hot-loader 搭建react开发环境
查看>>
Maven 插件
查看>>
初探Angular6.x---进入用户编辑模块
查看>>
计算机基础知识复习
查看>>
【前端词典】实现 Canvas 下雪背景引发的性能思考
查看>>
大佬是怎么思考设计MySQL优化方案的?
查看>>
<三体> 给岁月以文明, 给时光以生命
查看>>
Android开发 - 掌握ConstraintLayout(九)分组(Group)
查看>>
springboot+logback日志异步数据库
查看>>
Typescript教程之函数
查看>>
Android 高效安全加载图片
查看>>
vue中数组变动不被监测问题
查看>>
3.31
查看>>
类对象定义 二
查看>>
收费视频网站Netflix:用户到底想要“点”什么?
查看>>