服务器之家:专注于服务器技术及软件下载分享
分类导航

云服务器|WEB服务器|FTP服务器|邮件服务器|虚拟主机|服务器安全|DNS服务器|服务器知识|Nginx|IIS|Tomcat|

服务器之家 - 服务器技术 - Tomcat - Tomcat 检测内存泄漏实例详解

Tomcat 检测内存泄漏实例详解

2021-08-16 17:48Tomcat教程网 Tomcat

这篇文章主要介绍了 Tomcat 检测内存泄漏实例详解的相关资料,需要的朋友可以参考下

 tomcat如何检测内存泄漏

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

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

Tomcat 检测内存泄漏实例详解

如上图,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,属于内存泄漏的。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

延伸 · 阅读

精彩推荐