资讯专栏INFORMATION COLUMN

对于JVM,你就只知道堆和栈吗?

王笑朝 / 3402人阅读

摘要:下面的截图内容来自从规范我们可以看到,规范要求的运行时数据区域有程序计数器虚拟机栈堆方法区本地方法栈运行时常量池这及部分。查了一下,还是没有查到官方对于运行时数据区域的说明,但是许多博客都指出将字符串常量池移动到了堆中。

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

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

从JVM6规范,我们可以看到,规范要求的运行时数据区域有: PC Register(程序计数器)、Java Virtual Machine Stacks(java 虚拟机栈)、Heap(堆)、Method Area(方法区)、Native Method Stacks(本地方法栈)、Runtime Constant Pool(运行时常量池这及部分)。
注意标红部分,我们可以看到运行时常量池位于方法区内。
根据规范我们可以大概的画出JVM运行实数据区域(执行引擎、本地库接口在后面的文章中会进行详细介绍)。

在认真的看完JVM6、7、8的运行时数据区域规范之后,JVM6、7、8关于对运行时的数据区域要求一点变化都没有,还是程序计数器、Java虚拟栈、堆、方法区、本地方法栈、运行时常量池这几个部分。
那永久代是方法区的别名咯,准确的说是方法区的实现。规范是这么要求的,但是虚拟机会对这些区域进行调整,或者说是调整对JVM规范的实现。
查找了很多资料以后,还是没有找到官方对于永久代的描述(有找到官方文档关于永久代(Permanent Generation)的描述的,请联系我)。综合了很多博客和一些资料之后,我们可以做出如下判断,永久代是HotSpot虚拟机特有的概念,HotSpot团队使用永久代来实现JVM规范中的方法区。对于其他虚拟机来说是不存在永久代这个概念的。jdk8移除了永久代,关于这点我们将在后文进行详细的介绍。
那么为什么称方法区为永久代呢?
这跟GC分代收集有一定的关系,内存回收发生在方法区和堆中。
我们使用-XX:+PrintGCDetails参数,在IDEA中查看堆中的信息。

注意到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的测试例子

1.6结果: false
1.7以上的结果:true
我们来解释一下原因,1.6中字符串常量池放在永久代中和堆是隔离的。
我们来画个图来解释一下,
1.6

1.7的虚拟机做了调整,常量池中不需要在存储一份对象了,可以存储堆中的引用,更为灵活。
1.7及以上的图

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

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运行时区域有以下及部分:

方法区

java虚拟机栈

本地方法栈

程序计数器

运行时常量池(位于方法区中)

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77895.html

相关文章

  • 万万没想到,JVM内存结构的面试题可以问的这么难?

    摘要:方法区在实际内存空间站可以是不连续的。这一规定,可以说是给了虚拟机厂商很大的自由。但是值得注意的是,堆其实还未每一个线程单独分配了一块空间,这部分空间在分配时是线程独享的,在使用时是线程共享的。 在我的博客中,之前有很多文章介绍过JVM内存结构,相信很多看多我文章的朋友对这部分知识都有一定的了解了。 那么,请大家尝试着回答一下以下问题: 1、JVM管理的内存结构是怎样的? 2、不同的...

    CloudwiseAPM 评论0 收藏0
  • Java和栈

    摘要:每个栈中的数据原始类型和对象引用都是私有的,其他栈不能访问。栈分为三个部分基本类型变量区执行环境上下文操作指令。它用于存储已经被虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据。 Java的JVM的内存可分为三个区:堆(heap)、栈(stack)、方法区(method). 栈 每个线程包含一个栈区,栈中只保存方法中(不包括对象中的成员变量)的基础数据类型和自定义对象的引用,...

    Rango 评论0 收藏0
  • JVM的基本概念与维护调优

    摘要:栈因为是运行单位,因此里面存储的信息都是跟当前线程相关的信息。基本类型和对象的引用都是在存放在栈中,而且都是几个字节的一个数,因此在程序运行时,他们的处理方式是统一的。对象,是由基本类型组成的。 一、概念 数据类型 java虚拟机中,数据类型可以分为两类: 基本类型 引用类型 基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。基本类型包括:byte,sh...

    DevWiki 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<