当前位置: 首页 > 知识库问答 >
问题:

java - 求指导: 如何理解 这个 Tomcat中ThreadLocal引发的内存泄漏的问题?

蓝恩
2024-03-31

如何理解 这里的 Tomcat中的ThreadLocal引发的内存泄漏

这篇文章提到了ThreadLocal内存泄漏的问题(当然现在的Tomcat版本应该不会有这样的问题了): https://zhuanlan.zhihu.com/p/146410261,
不理解 “LeakingServlet 持有static 的MyThreadLocal ,导致myThreadLocal 的生命周期跟LeakingServlet 类的生命周期一样长。 ” Tomcat卸载应用的时候 LeakingServlet 和WebAppClassLoader 不应该一起被卸载了吗? LeakingServlet 不会被卸载吗?

按照我的理解: ClassLoader被卸载的前提是 他的class已经被卸载了。 但是 我们 更应该将 class和他的classLoader 作为一个整体, 如果class没有被引用 那么class可以被卸载,对应他的classLoader 可以被卸载。

Tomcat卸载引用, LeakingServlet 也应该被卸载吧?

https://cwiki.apache.org/confluence/display/tomcat/MemoryLeak...

d

共有1个答案

万俟炯
2024-03-31

LeakingServlet 和 WebAppClassLoader 的关系: 当Tomcat加载Web应用时,它会为每个Web应用创建一个WebAppClassLoader,这个类加载器负责加载并管理该Web应用的所有类,包括Servlet类如LeakingServlet。当Web应用需要停止或者重新部署时,Tomcat的目标确实是卸载WebAppClassLoader及其加载的所有类。

静态变量与类卸载: 当LeakingServlet含有一个静态的MyThreadLocal变量时,这个变量的生命周期将会变得非常长,因为它与类的生命周期绑定在一起。只要LeakingServlet类的类加载器(即WebAppClassLoader)还存在,这个静态变量就不会被垃圾回收。

内存泄漏的产生: 假设MyThreadLocal存储的对象与Web应用的上下文紧密相关,当Web应用停止时,这些对象本应随着Web应用一同释放。然而,由于静态MyThreadLocal的存在,它可能会持有对这些不应再被保留的对象的引用,从而阻止这些对象和WebAppClassLoader被垃圾回收,这就是所谓的内存泄漏。

Tomcat卸载过程中的问题: 即使在Tomcat试图卸载Web应用时,若存在这样的静态引用链路,LeakingServlet类虽然理论上不再被Web应用调用,但由于静态变量的作用,它依然有可能通过间接引用维持着与WebAppClassLoader之间的连接。因此,尽管Tomcat尝试卸载WebAppClassLoader及其加载的类,但由于静态引用的存在,部分资源可能无法被彻底释放,从而造成内存泄漏。

总结起来,尽管Tomcat在卸载Web应用时会尽力去卸载所有相关组件,但如果存在像静态ThreadLocal这样的引用陷阱,就可能导致部分对象和类加载器无法被正确地卸载和回收,从而出现内存泄漏。解决此问题的关键在于确保在Web应用停止时,所有与应用生命周期相关的资源都能够被正确地释放和解除引用。

您的理解基本正确,但需要细化一下:
在Java虚拟机(JVM)中,类的卸载并不直接决定类加载器的卸载,而是类加载器的活动性影响了其所加载的类能否被卸载。当一个类加载器加载的类及其所有实例都不再被任何强引用所引用时,这些类及其占据的内存理论上是可以被垃圾回收的。然而,如果类加载器自身作为GC Roots的一部分被保留下来,那么它加载过的类即便没有其他强引用也可能不会被卸载。

在Tomcat中,对于Web应用,当Web应用停止或重新部署时,Tomcat会尝试去卸载(unload)该Web应用相关的类加载器(WebAppClassLoader)。一旦WebAppClassLoader被卸载,它加载的所有类如果没有其他的类加载器引用,理论上都将符合卸载条件,也就是说这些类及其对应的实例可以被垃圾回收。

对于LeakingServlet,当Web应用被卸载时,如果LeakingServlet没有被其他地方引用,它应该是可以被卸载的。然而,如果正如之前所述的情况,LeakingServlet通过静态字段引用了ThreadLocal,而ThreadLocal又持有应用上下文或其他不应该长期存在的对象的引用,这就可能导致类加载器及其加载的类无法被有效卸载,从而形成内存泄漏。

所以结论是,LeakingServlet在正常情况下随着Web应用的卸载应该会被卸载,但如果存在上述不当引用情况,则可能会影响整个类加载器层次结构的卸载,从而产生内存泄漏问题。

 类似资料:
  • 我们已经设法摆脱了几乎所有的内存泄漏错误消息,但最后一个仍然被困住了。 2014年6月10日下午3:36:15 org.apache.catalina.loader.webappClassLoader checkThreadLocalMapForLeaks严重:web应用程序[/myapp]创建了一个ThreadLocal,其键类型为[com.sun.faces.application.appli

  • 我在Tomcat中得到了threadlocal内存泄漏错误,我正在使用ThreadPool,但在我的WebApp中没有threadlocal的实现。 严重:web应用程序[/mywebapp]创建了一个ThreadLocal,其键类型为[org.a pache.http.impl.cookie.dateformatholder$1](值为[org.apache.http.imp l.cookie.

  • 严重:web应用程序[]创建了一个ThreadLocal,其键类型为[com.box.sdk.boxDateFormat$1](值为[com.box.sdk.boxDateFormat$1@275AB696])和值类型为[java.text.SimpleDateFormat](值为[java.text.SimpleDateFormat@faabb360]),但在web应用程序停止时未能删除它。线程

  • 当关闭Tomcat时,我得到以下错误: 严重:web应用程序[App]创建了一个ThreadLocal,其键类型为[org.apache.logging.log4j.core.layout.PatternLayout$1](值为[org.apache.logging.log4j.core.layout.PatternLayout$1@14391AAF]),值类型为[java.lang.String

  • 严重:web应用程序创建了一个ThreadLocal,其键类型为[org.apache.log4j.helpers.ThreadLocalMap](值为[org.apache.log4j.helpers.ThreadLocalMap@3ac5b23e])和值类型为[java.util.Hashtable](值为[{userhost=192.168.15.90,userid=127,username

  • 本文向大家介绍Java中由substring方法引发的内存泄漏详解,包括了Java中由substring方法引发的内存泄漏详解的使用技巧和注意事项,需要的朋友参考一下 内存溢出(out of memory ) :通俗的说就是内存不够用了,比如在一个无限循环中不断创建一个大的对象,很快就会引发内存溢出。 内存泄漏(leak of memory) :是指为一个对象分配内存之后,在对象已经不在使用时未及