大家好,我是程序员牛肉。
最近在看一些讲解JVM的文章的时候,发现了一个很糟糕的现象:“大部分作者在介绍到JVM内存结构的时候,都不会标注对应的JDK版本”。
而JVM的内存结构实际上随着JDK的迭代是有一定的变更的。就导致一部分刚学习JVM的同学在这块会很懵逼。你能说出你现在所了解的JVM内存结构对应的是哪一个JDK版本的嘛?
因此我们这一篇就聚焦于介绍不同JDK版本下的JVM内存结构,让你真正的玩明白JVM的内存结构。
JDK1.6:
内存结构中的其他部分都大差不差的,因此我们就只介绍一下方法区:
-
方法区(Method Area)
-
作用
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它是各个线程共享的内存区域。
-
常量池
用于存放编译期生成的各种字面量和符号引用。字面量包括字符串常量、基本数据类型常量等,符号引用则用于指向类、方法、字段等。
需要注意的是:我们常说的“永久代”其实就指的是JDK1.6及以前版本中的方法区。那为什么要把JDK1.6及之前版本的方法区叫做永久代呢?
[“永久代”(Permanent Generation)这个概念出自 Java 虚拟机规范。在早期的 Java 虚拟机实现中,如 Sun 公司的 HotSpot 虚拟机,采用了永久代来实现方法区的功能,将其作为 JVM 内存结构的一部分进行管理和使用。]
而永久代有以下特点:
-
存储内容相对持久
永久代主要存储类的元数据、常量池、静态变量等信息。这些数据在整个应用程序的生命周期中通常是相对稳定和持久存在的,与应用程序的运行时间紧密相关,只要类被加载到 JVM 中,其相关的元数据等就会一直存在于永久代中,直到应用程序结束或者被卸载。
-
内存空间相对固定
在 JVM 的设计中,永久代的内存空间在 JVM 启动时就基本固定下来,不像堆内存那样可以根据应用程序的运行情况动态地扩展或收缩。这种相对固定的内存分配方式也体现了其 “永久” 的特性,给人一种它会在 JVM 运行期间一直存在且大小相对稳定的感觉。
最初将永久代的内存空间设置成为固定的也是有一定的原因的。这种设计使得JVM在启动的时候可以预先分配好内存给永久代直接使用,使得内存分配更加可预测。
但是随着技术的发展,这种固定内存大小的永久代开始逐渐暴漏劣势。
例如由于其内存空间是固定的,就会导致当应用程序加载了大量的类或者大量使用反射时,永久代很容易发生溢出。这种溢出会导致OutOfMemoryError异常,而调整永久代的大小需要手动设置JVM参数,这在一定程度上增加了配置的复杂性。
而且永久代的调优也很困难,永久代的回收主要包括对类的卸载和对常量池的回收。而其是跟着老年代一起回收的。如果永久代太大,那么老年代相对来说就会比较小,容易导致老年代溢出;而如果永久代太小,其本身又很容易溢出。
既然永久代已经出现这么明显的缺陷了,那么肯定是要弃用它的。因此我们基本可以认为:后续无论是JDK1.7的变更还是JDK1.8的变更,核心变更内容都是逐渐弃用永久代
让我们来看看JDK1.7的JVM内存结构:
我们可以发现:JDK1.7的主要变化就是将原本存储在永久代中的字符串常量和静态变量取了出来,单独在堆中开了一块区域来存储。
此时存放在方法区的还有运行时常量池和类常量池:
- 运行时常量池(Runtime Constant Pool):
- 这是方法区的一部分,用于存储编译期生成的各种字面量和符号引用。在JDK 1.7中,运行时常量池仍然位于方法区,但在JDK 1.8中,它被移动到了堆内存中。
- 类常量池(Class Constant Pool):
- 类常量池是类文件的一部分,存储在方法区中。它包含了类、方法、字段的引用等信息。
JDK1.7其实更像是一个过渡版本,在这个版本中逐渐开始减少对永久代的依赖。在验证了有效性之后,JDK1.8终于直接对永久代下刀了:
JDK1.8的JVM内存结构:
相比较于JDK1.7,我们废弃了永久代的使用,转而让元空间来代替永久代的职能。那元空间相比较于永久代有什么优势呢?
它与持久代最大的区别在于:元空间并不在虚拟机内存中而是使用本地内存。因此Metaspace具体大小理论上取决于你的电脑系统可用内存的大小,可见也不是无限制的,需要配置参数。
-XX:MaxMetaspaceSize=xxx
根据官方文档描述:删除永久代的目的也是为了是促进 JRockit和Hotsopt的融合工作。
对应的文档
[JRockit是一个全面的Java运行时解决方案组合,包括了行业最快的标准Java解决方案。 大量的行业基准测试显示,基本JRockit JVM是世界上最快的JVM。JRockit面向延迟敏感型应用的解决方案JRockit Real Time提供以毫秒或微秒级的JVM响应时间,适合财务前端办公、军事指挥与控制和电信网络的需要。使用JRockit产品,客户已经体验到了显著的性能提高(一些超过了70% )和硬件成本的减少(达50%)。]
那今天关于JVM运行区域的文章就介绍到这里了,相信通过我的介绍,你已经大致了解了不同JDK版本之间的JVM内存区域差别。希望我的文章可以帮到你。
对于JVM内存区域,你还有什么想说的嘛?欢迎在评论区留言。