不少java程序员一提JVM运行时数据区域,就会说堆和栈,当然也有java程序员给出方法区、虚拟机栈、本地方法栈、堆、程序计数器这个答案,但是还有人给出永久代、虚拟机栈、本地方法栈、堆、程序计数器这个答案。那么究竟哪种答案是正确的呢?

首先我们介绍两个概念,这对于我们回答上面的问题来说是必不可少的。
1.虚拟机: 简单的说虚拟机是一种抽象的计算机。
2.Java虚拟机规范: 虚拟机规范是一种对Java虚拟机的约束,Java虚拟机负责对虚拟机规范进行实现。
我们平常所说JAVA虚拟机一般是指的一种具体的JAVA虚拟机规范的实现,比如说HotSpot。当然市面上还有其他的Java虚拟机。
下面的截图内容来自https://docs.oracle.com/javas...
clipboard.png

从JVM6规范,我们可以看到,规范要求的运行时数据区域有: PC Register(程序计数器)、Java Virtual Machine Stacks(java 虚拟机栈)、Heap(堆)、Method Area(方法区)、Native Method Stacks(本地方法栈)、Runtime Constant Pool(运行时常量池这及部分)。
注意标红部分,我们可以看到运行时常量池位于方法区内。
根据规范我们可以大概的画出JVM运行实数据区域(执行引擎、本地库接口在后面的文章中会进行详细介绍)。
clipboard.png
在认真的看完JVM6、7、8的运行时数据区域规范之后,JVM6、7、8关于对运行时的数据区域要求一点变化都没有,还是程序计数器、Java虚拟栈、堆、方法区、本地方法栈、运行时常量池这几个部分。
那永久代是方法区的别名咯,准确的说是方法区的实现。规范是这么要求的,但是虚拟机会对这些区域进行调整,或者说是调整对JVM规范的实现。
查找了很多资料以后,还是没有找到官方对于永久代的描述(有找到官方文档关于永久代(Permanent Generation)的描述的,请联系我)。综合了很多博客和一些资料之后,我们可以做出如下判断,永久代是HotSpot虚拟机特有的概念,HotSpot团队使用永久代来实现JVM规范中的方法区。对于其他虚拟机来说是不存在永久代这个概念的。jdk8移除了永久代,关于这点我们将在后文进行详细的介绍。
那么为什么称方法区为永久代呢?
这跟GC分代收集有一定的关系,内存回收发生在方法区和堆中。
我们使用-XX:+PrintGCDetails参数,在IDEA中查看堆中的信息。
clipboard.png
注意到PSYoungGen和ParOldGen这两个单词,从控制台的信息我们可以看出堆中的区域划分
PSYoungGen

eden space
from space
to    space

ParOldGen
PS和Par代表垃圾回收器
也就是说堆里面又可以再分为年轻代、老年代,堆是垃圾回收机制的重点区域,将方法区也纳入垃圾回收范围,与年轻代、老年代相对,称方法区为永久代。
这就是永久代的来历。
接下来介绍一下JVM1.7和1.6的不同。
在介绍JVM1.6和1.7的区别之前,我们先介绍String类的intern()方法
字符串在调用该方法的时候,如果字符串常量池里面还没有该字符串,则将该字符串添加进字符串常量池中。
查了一下,还是没有查到HotSpot官方对于运行时数据区域的说明,但是许多博客都指出jdk1.7将字符串常量池移动到了堆中。
以下是分别在1.6、1.8的测试例子
clipboard.png
1.6结果: false
1.7以上的结果:true
我们来解释一下原因,1.6中字符串常量池放在永久代中和堆是隔离的。
我们来画个图来解释一下,
1.6
clipboard.png
1.7的虚拟机做了调整,常量池中不需要在存储一份对象了,可以存储堆中的引用,更为灵活。
1.7及以上的图

clipboard.png

请看下一张图。
jdk版本在1.8。MetaSpace是什么鬼?

clipboard.png

Jdk1.8移除了永久代或者说用MetaSpace去实现虚拟机规范中的方法区。
详见:JEP 122: Remove the Permanent Generation
我查了很多资料,还是没有找到官方对MetaSpace的解释和描述,到是在深入探究 JVM | 探秘 Metaspace这篇博客中看到了MetaSpace的相关描述。

In JDK 8, classes metadata is now stored in the native heap and this space is called Metaspace.

字符串常量池仍然在堆中,方法区移动至MetaSpace中
那么如果有人问你JVM运行时区域由几部分组成,那么应该如何回答呢?
我认为答案可以是这样的:JVM规范中的要求JVM运行时区域有以下及部分:

  1. 方法区
  2. java虚拟机栈
  3. 本地方法栈
  4. 程序计数器
  5. 运行时常量池(位于方法区中)

但是不同的虚拟机对规范有着不同的实现,HotSpot1.6对方法区的实现叫永久代,1.7将字符串常量池移动到了堆中,1.8移除了永久代改用元数据区实现方法区,字符串常量池仍然在堆中。


北冥有只鱼
147 声望35 粉丝