基于《深入理解Java虚拟机》第三版 结论:
1.7之前静态变量在方法区 1.7以及之后在堆中
原方法区其他信息在堆外内存
首先方法区是什么:
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载 的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。虽然《Java虚拟机规范》中把 方法区描述为堆的一个逻辑部分,但是它却有一个别名叫作“非堆”(Non-Heap),目的是与Java堆区 分开来。
2.2.5方法区第二段中描述道
考虑到HotSpot未来的发展,在JDK 6的 时候HotSpot开发团队就有放弃永久代,逐步改为采用本地内存(Native Memory)来实现方法区的计 划了[1],到了JDK 7的HotSpot,已经把原本放在永久代的字符串常量池、静态变量等移出,而到了 JDK 8,终于完全废弃了永久代的概念,改用与JRockit、J9一样在本地内存中实现的元空间(Meta space)来代替,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。
注意此处说的是 永久代的字符串常量池、静态变量等移出 类型信息 迁移到 元空间中
静态变量移出到哪里?
4.3.1中做出了一个实验:
证明了静态变量的值如果是对象的情况下,是存在于堆中的。 “从《Java虚拟机规范》所定义的概念模型来看,所有Class相关的信息都应该存放在方法区之中, 但方法区该如何实现,《Java虚拟机规范》并未做出规定,这就成了一件允许不同虚拟机自己灵活把握的事情。JDK 7及其以后版本的HotSpot虚拟机选择把静态变量与类型在Java语言一端的映射Class对象存放在一起,存储于Java堆之中,从我们的实验中也明确验证了这一点”
7.3.3进一步总结
准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初 始值的阶段,从概念上讲,这些变量所使用的内存都应当在方法区中进行分配,但必须注意到方法区 本身是一个逻辑上的区域,在JDK 7及之前,HotSpot使用永久代来实现方法区时,实现是完全符合这 种逻辑概念的;而在JDK 8及之后,类变量则会随着Class对象一起存放在Java堆中,这时候“类变量在 方法区”就完全是一种对逻辑概念的表述了