JDK 6 之前的 HotSpot VM,静态变量保存在类的元数据 InstanceKlass 的末尾

JDK 7 之后的 HotSpot VM,静态变量则是保存在类的 Java 镜像 java.lang.Class 实例的末尾

在 HotSpot VM 中,Java 对象 Java object、类的元数据 InstanceKlass、类的 Java 镜像 Java mirror 三者的关系如下

Java object      InstanceKlass       Java mirror
 [ _mark  ]                          (java.lang.Class instance)
 [ _klass ] --> [ ...          ] <-\              
 [ fields ]     [ _java_mirror ] --+> [ _mark  ]
                [ ...          ]   |  [ _klass ]
                                   |  [ fields ]
                                    \ [ klass  ]

假如有下面这段代码

class A {
	static int value = 1;
}

在 JDK 6 前,是这样的:

Java object      InstanceKlass       Java mirror
 [ _mark  ]                          (java.lang.Class instance)
 [ _klass ] --> [ ...          ] <-\              
 [ fields ]     [ _java_mirror ] --+> [ _mark  ]
                [ ...          ]   |  [ _klass ]
                [ A.value      ]   |  [ fields ]
                                    \ [ klass  ]

在 JDK 7 后,则是这样的:

Java object      InstanceKlass       Java mirror
 [ _mark  ]                          (java.lang.Class instance)
 [ _klass ] --> [ ...          ] <-\              
 [ fields ]     [ _java_mirror ] --+> [ _mark   ]
                [ ...          ]   |  [ _klass  ]
                                   |  [ fields  ]
                                    \ [ klass   ]
                                      [ A.value ]

那么,InstanceKlassjava.lang.Class 实例都是放在哪里呢?

  • 对于 InstanceKlass

    • JDK 7 前的 HotSpot VM 里,它是存放在 GC 堆中所谓的永久代 Permanent Generation (简称PermGen)中

    • JDK 8 后的 HotSpot VM 则完全移除了永久代,它改为存放在本地内存 Native Memory 中的元空间 Metaspace

      (方法区的一种实现方式)

  • 对于 java.lang.Class 实例对象

    • 它从来都只是普通的 Java 对象,一样存放在 GC 堆里

上面的分析比较绕,总结一下静态变量在 JVM 内存区域的位置:

JDK 6

堆中的永久代(方法区)

此时方法区(用永久代来实现)被视作堆的一个逻辑部分

JDK 7

堆(Class 对象)

废除永久代,方法区用元空间实现,静态变量跟随 Class 对象移到堆中

JDK 8 ~ 至今

堆(Class 对象)

另外,关于 JVM 内存区域中 堆、方法区、永久代 之间的关系比较复杂,需要结合周志明老师的《深入理解 Java 虚拟机》帮助理解

参考:https://www.zhihu.com/question/50258991