静态变量存储位置随jdk版本变化:jdk 7及以前在永久代(方法区),jdk 8+移至堆中,元空间仅存类元数据;物理实现变迁影响oom类型与调优策略。

静态变量的存储位置不是一成不变的,它取决于你使用的 JDK 版本。
JDK 7 及以前:静态变量在方法区(永久代)
那时方法区由“永久代”(PermGen)实现,静态变量和类元数据(如常量池、字段描述符)一起存放在其中。变量本身(基本类型值或引用地址)直接落在永久代里。
- 例如 static int count = 10; —— 数值 10 存在永久代
-
static List
cache = new ArrayList(); —— 引用 cache 存在永久代,而 new 出来的 ArrayList 实例仍在堆中 - OOM 错误提示通常是:java.lang.OutOfMemoryError: PermGen space
JDK 8 及以后:静态变量实际在堆中
永久代被移除,元空间(Metaspace)取而代之,只存放类结构信息(Klass、符号表、常量池等),不再容纳任何静态变量。Class 对象连同它的所有 static 字段,都分配在 Java 堆上。
- static final byte[] DATA = new byte[1MB]; —— 数组对象和字段引用全在堆中
- GC 可以统一管理这些静态引用,但只有当 ClassLoader 被卸载、类真正卸载时,它们才可能被回收
- OOM 错误提示变为:java.lang.OutOfMemoryError: Java heap space(若因静态集合膨胀)或 java.lang.OutOfMemoryError: Metaspace(与静态变量无关,多因动态生成类)
为什么说法不一致?关键看“方法区”的定义
JVM 规范说静态变量属于“方法区”,这是逻辑概念;而具体物理实现随版本演进:
- 规范层面:静态变量是类元数据的一部分,语义上归入方法区
- 物理层面:JDK 7 起已迁入堆;JDK 8+ 明确由堆承载,元空间纯做类描述
- 面试或考试未指明版本时,“方法区”是传统标准答案;排查生产问题必须按实际 JDK 版本判断真实内存位置
对开发的实际影响
存储位置变化直接影响调优和问题定位:
- 堆溢出要检查静态集合是否持续 add 未清理(如 static Map 缓存未设上限)
- 元空间溢出和静态变量无关,应排查 CGLIB 动态代理、反射大量加载类等行为
- JDK 8+ 需分开配置:-Xmx 控制堆大小,-XX:MaxMetaspaceSize 控制元空间上限
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











