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

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

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

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

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

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

image.png

Jdk1.8移除了永久代或者说用MetaSpace去实现虚拟机规范中的方法区。 详见:[JEP 122: Remove the Permanent Generation][1] 我查了很多资料,还是没有找到官方对MetaSpace的解释和描述,到是在[深入探究 JVM | 探秘 Metaspace][2]这篇博客中看到了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移除了永久代改用元数据区实现方法区,字符串常量池仍然在堆中。 [1]: openjdk.java.net/jeps/122[2]: www.sczyh30.com/posts/Java/…
相关文章
|
2月前
|
存储 算法 Java
散列表的数据结构以及对象在JVM堆中的存储过程
本文介绍了散列表的基本概念及其在JVM中的应用,详细讲解了散列表的结构、对象存储过程、Hashtable的扩容机制及与HashMap的区别。通过实例和图解,帮助读者理解散列表的工作原理和优化策略。
49 1
散列表的数据结构以及对象在JVM堆中的存储过程
|
2月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
488 1
|
5月前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
162 4
|
5月前
|
存储 Java Linux
32 位和 64 位 JVM 的最大堆大小是多少?
【8月更文挑战第22天】
281 0
|
2月前
|
存储 监控 Java
合理设置JVM堆大小
合理设置JVM堆大小
55 4
|
3月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
137 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
3月前
|
算法 Java
JVM进阶调优系列(3)堆内存的对象什么时候被回收?
堆对象的生命周期是咋样的?什么时候被回收,回收前又如何流转?具体又是被如何回收?今天重点讲对象GC,看完这篇就全都明白了。
|
5月前
|
存储 安全 Java
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别;什么是程序计数器,堆,虚拟机栈,栈内存溢出,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
|
5月前
|
存储 Java
JVM中的堆
这篇文章详细介绍了JVM中的堆内存,包括堆的核心概念、内存细分、堆空间大小设置以及Java 7和8版本堆内存逻辑上的不同划分。
JVM中的堆
|
6月前
|
Java
Jinfo 查看 jvm 配置及使用 Jstat 查看堆内存使用与垃圾回收
Jinfo 查看 jvm 配置及使用 Jstat 查看堆内存使用与垃圾回收
183 5