tomcat如何检测内存泄漏
一般情况下,如果我们重启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对象回收。
简单的实现代码大致如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class memoryleaktest{ private map<classloader, string> childclassloaders = new weakhashmap<classloader, string>(); public string[] findreloadedcontextmemoryleaks() { system.gc(); list<string> result = new arraylist<string>(); for (map.entry<classloader, string> 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,属于内存泄漏的。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!