Web应用重新部署时静态变量内存泄漏的根本原因是静态字段绑定类加载器,旧ClassLoader未回收导致其持有对象图无法释放;表现为堆内存阶梯式上涨、Full GC无效、Metaspace持续增长,可通过jstat、jcmd、MAT分析定位static Map/List/ThreadLocal等高危结构,并在contextDestroyed中清理或改用弱引用修复。

Web 应用重新部署时,静态变量引发的内存泄漏往往表现为:每次 redeploy 后堆内存持续上涨、GC 效率下降、最终触发 OutOfMemoryError: Java heap space 或 java.lang.OutOfMemoryError: Metaspace。根本原因在于——静态字段绑定的是类加载器(ClassLoader),而旧应用的 ClassLoader 未被回收,其持有的静态引用连带整个对象图无法释放。
确认是否是 redeploy 导致的泄漏
先排除其他干扰因素,聚焦 redeploy 场景:
- 观察 JVM 进程是否复用(如 Tomcat 默认复用 JVM);若每次部署都重启 JVM,则静态变量问题基本不存在
- 检查应用服务器日志,确认是否有 “previous web application is still alive”、“leaked classloader” 类提示(Tomcat 日志中常见)
- 对比两次 redeploy 后的
jstat -gc <pid>输出:老年代(Old Gen)使用量是否阶梯式上升,且 Full GC 后回收极少 - 用
jcmd <pid> VM.native_memory summary查看 metaspace 是否持续增长,暗示类加载器泄漏
定位泄漏源头的静态字段
关键不是“哪个类有 static”,而是“哪个 static 字段持有了不该持有的对象”:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 生成 redeploy 后的 heap dump(推荐
jmap -dump:live,format=b,file=after-redeploy.hprof <pid>) - 用 Eclipse MAT 打开,执行 Leak Suspects Report,重点关注 “ClassLoader Leak” 相关提示
- 在 Dominator Tree 中筛选
org.apache.catalina.loader.WebappClassLoader(或对应容器的类加载器),右键 → “Merge Shortest Paths to GC Roots” → 勾选 “exclude weak/soft references” - 重点查看路径中出现的
static字段,尤其是static Map、static List、static Cache、static ThreadLocal等
检查典型高危静态结构
这些结构在 redeploy 时极易成为泄漏枢纽:
立即学习“Java免费学习笔记(深入)”;
-
静态集合未清空:如
public static final Map<String, Object> CACHE = new HashMap<>();—— redeploy 后新 ClassLoader 加载的类仍可能往里面 put,但旧 ClassLoader 的缓存实例无法释放 -
静态监听器/回调注册未注销:例如向全局事件总线注册了 static listener,但未在
ServletContextListener.contextDestroyed()中反注册 - 静态线程或线程池未 shutdown:static ExecutorService 持有 Runnable,而 Runnable 又隐式持有 ServletContext 或 Spring ApplicationContext 引用
-
静态单例持有 Web 资源:如自定义的 static ConfigManager 持有
ServletContext、DataSource或Spring BeanFactory
验证与修复建议
修复不是简单删掉 static,而是切断 ClassLoader 与静态引用的强绑定:
- 在应用卸载时主动清理:在
ServletContextListener.contextDestroyed()或 Spring@PreDestroy方法中,对静态集合调用clear(),对静态线程池调用shutdownNow() - 改用弱引用或软引用:如用
static Map<K, WeakReference<V>>替代强引用,或用WeakHashMap存储临时上下文对象 - 避免在静态字段中直接持有容器资源:不存
ServletContext、ApplicationContext,改用查找式访问(如WebApplicationContextUtils.getRequiredWebApplicationContext(sc)) - 启用 ClassLoader 泄漏检测:Tomcat 可配置
-Dorg.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false(仅调试用),或使用org.apache.tomcat.util.scan.StandardJarScanner排查扫描器泄漏

















