静态变量逻辑上属方法区(类级别数据),物理位置随JDK版本变化:JDK 6及以前在永久代,JDK 7起移至堆,JDK 8+全部存于堆中,元空间仅存类元数据。

Java 中静态变量的存放位置,不能简单回答“方法区”或“堆”,而要结合 JVM 版本看实际实现——逻辑上属于方法区(类级别数据),物理上 JDK 8+ 全部在堆中。
静态变量的本质是类级别的数据
它不依赖对象存在,随类加载而初始化,随类卸载而回收。JVM 规范将其归入“方法区”语义范畴,但方法区是逻辑概念,不同 JDK 版本底层实现不同:
- JDK 6 及以前:静态变量存于永久代(PermGen),和类元数据一起放在方法区
- JDK 7:静态变量从永久代迁出,移至堆内存;常量池也部分移到堆
- JDK 8+:永久代被彻底移除,改用元空间(Metaspace),但它只存类结构(如 Klass、符号表、字段描述符),所有静态变量(包括基本类型值和引用)都作为 Class 对象的一部分,存于堆中
✅ 举例:
public static final byte[] CONFIG = new byte[1024*1024];
——CONFIG这个字段的引用 + 它指向的byte[]数组,全部在堆里;元空间里只有Test.class的结构信息,没有这个数组。
为什么 Metaspace OOM 和静态变量无关?
-
-XX:MaxMetaspaceSize控制的是元空间大小,影响因素是加载的类数量(比如反射、动态代理、OSGi 场景) - 大量静态集合(如
static Map<string bigobject></string>)撑爆的是堆,报错是:java.lang.OutOfMemoryError: Java heap space - 所以调优时:
- 堆溢出 → 检查静态缓存是否泄漏、未清理
- Metaspace 溢出 → 检查类加载器是否未释放、是否频繁生成新类
实际开发中怎么判断?
- 看 JVM 版本:当前主流是 JDK 17/21,全部走 堆 + 元空间 模式
- 看错误日志:OOM 提示明确区分
Java heap space和Metaspace - 看监控工具:JConsole / VisualVM 中,“Classes”页显示元空间使用,“Heap Memory”页包含所有静态字段占用
- 不需要额外参数控制静态变量位置:它自动跟随 Class 对象分配,无法单独配置
不复杂但容易忽略


















