死磕P7:JVM内存区域划分(一)

p7   jvm   java  
发布于 Sep 22, 2024

这是「死磕P7」系列第 001 篇文章,欢迎大家来跟我一起 死磕 100 天,争取在 2025 年来临之际,给自己一个交代。

JVM 内存区域划分是面试常考点,属于死记硬背型,比较让人头大的是不同版本的 JDK 具有不同的划分方式,主要矛盾点就来自 方法区,永久代,元空间 这几个破玩意。

整理了一些比较靠谱的资料,进行了一些汇总,第一方便自己记忆,第二也希望大家不要再为内存区域划分的面试而苦恼。

虚拟机规范定义

先来看一下《Java 虚拟机规范》定义的概念,规范和具体实现是两回事,可以理解为规范是接口定义,具体的虚拟机实现是接口的实现类,实现细节千差万别,如 HotSpot VM, JRockit VM, Graal VM 等等(这些知道一下就好)。

程序计数器,虚拟机栈,本地方法栈基本没啥争议点,也比较好记,并且他们是属于线程隔离的(线程独享,一人一杯奶茶,各喝各的)

主要容易搞混的是 方法区 和 堆,究其原因其实就是因为版本更新导致的,一般大家说的都是 HotSpot VM, 下面用图示的方式告诉您不同版本的区别是什么。

JDK 1.6 内存划分

JDK 1.6 JVM 运行时内存就分为方法区(也叫永久代),堆,虚拟机栈,本地方法栈,程序计数器

JDK 1.7 内存划分

JDK 1.7 中将方法区中的字符串常量池和静态变量等存储区域调整到了堆中,方法区中只保留了类型信息,划分区域仍然是方法区(也叫永久代),堆,虚拟机栈,本地方法栈,程序计数器,唯一的区别就是方法区里面放置的内容减少了,如下图

JDK 1.8 内存划分

JDK 1.8 中将方法区直接移出了 JVM 内存,直接放置到了 物理内存 中,并且改名叫元空间(Meta Space),也就没有了永久代的叫法(当然,你要称元空间就是永久代也不算错,就好比你小时候一直被大家叫:狗蛋,长大了回老家,老同学还这么叫你一样,哈哈)

为什么做这些改动?

大概了解一点就行,我们又不是设计开发 JVM 的,别人给我们啥就用啥好了!

原因大概有以下几点:

  • Oracle 收购了两种 JVM:HotSpot VM 和 JRockit VM,并且想要将它们整合,但二者方法区实现差异较大;
  • 字符串存在永久代中,容易出现性能问题和 OOM;
  • 类及方法的信息大小较难确定,永久代大小难以确定:太小易导致永久代溢出,太大则易导致老年代溢出(JVM 内存是有限的,此消彼长);
  • 永久代会为垃圾回收带来不必要的复杂度,且回收效率较低(性价比低)。

总结

JVM 内存划分一直都是考点,当然考得不仅仅是上面简单的怎么划分的,今天主要让大家彻底搞懂不同版本 JVM 之间的划分差异,做到了然于胸,不再为网上的乱七八糟的文章所困惑(感觉大家写的又对又不对,比较乱)。

下一篇我们会继续解读 JVM 的内存划分,主要介绍各区域的一些特点。

本次的分享到此结束,希望对你有所帮助。

如果你对我分享的内容感兴趣,欢迎扫码关注公众号:新质程序猿,并设置星标,推送更实时哟!

本文由 黄彦祥 创作,采用 知识共享署名 3.0 中国大陆许可协议 进行许可。
可自由转载、引用,但需署名作者且注明文章出处。