商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 静态变量的生命周期:分析它与类对象 Class 在堆中的绑定关系与回收时机

静态变量的生命周期:分析它与类对象 Class 在堆中的绑定关系与回收时机

  发布于2026-07-03 阅读(0)

扫一扫,手机访问

静态变量在 Ja va 里是个挺特别的存在——它的生命周期,其实跟堆里的那些实例对象没半毛钱关系。你可能会想,它什么时候生、什么时候死?说到底,得看它所属的那个 Class 对象在 JVM 里还能不能“活着”。

静态变量的生命周期与类相同,从类加载时初始化,存储于方法区(元空间),随类卸载而销毁;其存在依赖Class对象是否被JVM强引用,通常持续至JVM退出。

静态变量的生命周期:分析它与类对象 Class 在堆中的绑定关系与回收时机

换句话说,静态变量不会因为某个对象被回收而消失,也不会因为你 new 了一个实例就凭空变出来。它的整个生命周期,完全取决于 JVM 对那个 Class 对象的引用情况。

静态变量在类加载时初始化,存储于方法区

当 JVM 第一次“真正用上”某个类时——比如调用它的静态方法、访问它的静态字段、或者 new 一个对象、通过反射获取 Class 对象——就会触发类加载流程:加载 → 链接(验证、准备、解析)→ 初始化。注意,在“准备”阶段,静态变量就已经被分配好内存,并且设好默认值了;到了“初始化”阶段,才会执行 static {} 代码块和静态字段的显式赋值。

这时候,静态变量实际上存放在方法区里(JDK 8 以后是元空间),跟堆内存没什么关系。它属于类本身,所有实例共享同一份数据。一个类只此一份,多少实例来了都一样。

静态变量的存活依赖 Class 对象是否可达

静态变量不会被垃圾回收器单独处理——它没那么特殊。但它的“存在状态”直接由其所属的 Class 对象决定:只要这个 Class 对象还被强引用拿着,静态变量就一直有效。而 Class 对象能不能被卸载,得同时满足三个条件:

  • 该类所有实例都已被 GC 回收,堆里一个不剩
  • 加载该类的 ClassLoader 实例本身也被 GC 回收了
  • 该类的 Class 对象不再有任何强引用——包括 MyClass.class、静态字段里持有该 Class 的引用、以及反射调用留下的痕迹等

这三条缺一不可。只要有一条不满足,类就赖着不走,静态变量自然也就一直活在方法区里。

常见导致静态变量长期驻留的场景

现实开发中,有些情况会让静态变量“意外长寿”,甚至变成内存泄漏的源头:

  • 静态变量直接持有本类或子类的实例引用——这就在 Class 对象和实例之间形成了一条双向强引用链,谁都别想逃
  • 自定义的 ClassLoader 没被释放,而它加载的类里还有静态引用,整个加载器链都拽着不放
  • 通过 ThreadLocal、监听器、回调接口等方式,间接引用了静态变量关联的对象
  • 在 Android 开发中,Application 或 Activity 的静态引用没及时清理,配置变更或者进程后台驻留时就容易出问题

这些场景的本质都一样:让 Class 对象始终可达,从而阻止类卸载。

回收时机:仅发生在类卸载时,通常等于 JVM 退出

在绝大多数标准 Ja va 应用里——尤其是用了 Spring 这种单例容器的项目——系统类加载器(Bootstrap、Extension、AppClassLoader)的生命周期和 JVM 是一体的,压根不会被回收。所以这些类加载器加载的类几乎永远不会被卸载,静态变量也就永远待在那里。

只有在那些动态类加载的场景下——比如 OSGi 容器、热部署环境、或者你自己用自定义 ClassLoader 配合弱引用管理——才有可能触发类卸载。一旦类被卸载,静态变量占用的方法区内存才会真正被释放。

简单总结一下:静态变量不归 GC 管,它归类加载器和 Class 对象管。它什么时候消失,取决于那个类什么时候真正“退场”。而大多数时候,退场时刻就是 JVM 关闭的那一刻。

本文转载于:https://www.php.cn/faq/2458856.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注