Spring Boot 2.5部署Tomcat9重部署时日志相关永久代内存泄漏问题
Spring Boot 2.5 war包部署Tomcat 9类加载器泄漏解决方案
配置补全步骤
1. 日志框架生命周期托管配置
你已添加log4j-web依赖但未生效,是因为缺少显式的容器监听器配置,需要在项目WEB-INF/web.xml中添加对应日志框架的生命周期监听器,由Tomcat在应用卸载时主动销毁日志上下文:
- Log4j2 配置:
<listener> <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class> </listener> <context-param> <param-name>log4j2.isWebApp</param-name> <param-value>true</param-value> </context-param>
- Logback 配置:
<listener> <listener-class>ch.qos.logback.classic.servlet.LogbackServletContextListener</listener-class> </listener>
同时在application.properties中禁用Spring Boot自带的日志自动初始化,避免重复注册资源:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.logging.LoggingAutoConfiguration
2. 开启JVM类卸载参数
你观察到无强引用但ParallelWebappClassLoader实例残留,大概率是未开启JVM类卸载开关,需要在CATALINA_OPTS中补充以下参数:
# 通用类卸载参数 -XX:+ClassUnloading -XX:+ClassUnloadingWithConcurrentMark # 若使用CMS垃圾回收器额外添加 -XX:+CMSClassUnloadingEnabled # 若使用JDK 8+ 还可添加元空间回收参数 -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=512M
Java 8之后永久代被元空间替代,默认不会主动卸载未使用的类,只有开启上述参数后,无引用的类加载器关联的类才会被GC回收。
3. Tomcat容器配置优化
在Tomcat的conf/server.xml中补充配置,提升重部署时的资源清理效率:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" undeployOldVersions="true"> <Context path="" reloadable="true" antiResourceLocking="true" /> <!-- 原有其他配置 --> </Host>
额外排查方向
如果完成上述配置后仍有泄漏,可优先排查以下场景:
- 应用内是否有自定义线程池未在
ServletContextListener的销毁方法中主动关闭,存活线程的上下文类加载器会持有ParallelWebappClassLoader的引用 - 是否引入了包含静态缓存的第三方组件,缓存中持有应用内类的实例,未在应用卸载时主动清空缓存
- 是否有自定义的JMX Bean未在应用卸载时主动注销,JVM的MBeanServer会持有Bean的强引用
内容的提问来源于stack exchange,提问作者Sam Webb
相关产品推荐
相关产品推荐

