JVM HotSpot 之 内存结构演进过程

11 篇文章 0 订阅

1、前提

如题,此文的内容是基于 SUN JVM HotSpot

2、JVM 体系结构

首先,简单说下JVM的体系结构,JVM 主要分为三个系统:类加载器子系统、运行时数据区、执行引擎,如下图:
在这里插入图片描述

本文要讲的 「内存结构」 属于 「运行时数据区」

3、演进

在网上找到一张 1.6、1.7、1.8 的演进过程(原图出处: https://www.jianshu.com/p/8d24230767a4 )。觉得还是很清晰的,这里那里引用下:)。
图1
依据上图的内容,我又梳理了一个差异表格,如下:
图2

通过上边表格我们可以看出来,1.6、1.7、1.8 这三个版本,变化最大的是 「方法区」「元空间」。1.8 用 「元空间」 取代了 「方法区(永久代)」,如下图:
在这里插入图片描述

在 1.8 中,内存结构主要由三大块组成:堆内存、元空间、栈。这里堆内存占据了最大的一块儿区域,Ta 由 新生代老年代 组成,分别占据了堆内存空间的 1/3 和 2/3 。而 新生代 又分为三个部分,Eden、From Survivor、To Survivor,他们占据新生代空间的比例为 8:1:1(可调节)。
图4
我们可以通过以下几个参数来对 堆内存(Heap) 的空间进行设置,如下:

参数名描述
-XmsJVM初始分配的内存,默认是物理内存的1/64
-XmxJVM最大分配的内存,默认是物理内存的1/4
-XmnJVM新生代分配的内存,默认是堆内存的1/3

在 JVM 的参数中没有专门用来设置 老年代 大小的,但是我们可以通过公式 -Xmx = -Xmn + 老年代 这个公式,来得知 -Xmx 减去 -Xmn 就是老年代的大小了。

默认空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限制;空余堆内存大于 70% 时,JVM 会减小堆直到 -Xms 的最小限制。所以服务器通常设置 -Xms 与 -Xmx 相等以免在每次 GC 后调整堆的大小。

4、对「方法区」、「永久代」、「元空间」的理解

4.1 方法区

在 Java 虚拟机中,方法区是一块儿可供 各线程共享运行时数据区。不同的 JVM 版本,方法区中存储的数据略有不同(详见上图)。

方法区 作为一个概念在 《Java虚拟机规范》只是规定它的作用,但是并没有规定怎么去实现 Ta。这样就造成了各个 JVM 厂家,对自家的 JVM 中的 方法区 的实现也各不相同。

在《Java虚拟机规范》中 Ta 被描述为 堆(Heap) 的一个逻辑部分,Ta 还有一个别名叫 Non-Heap(非堆),这是为了与 Java Heap 来做区分。

4.2 永久代(PermGen)

这里的 永久代 其实就是 Sun 推出的 JVM 产品 HotSpot 对 方法区 的实现,其他虚拟机实现并没有 永久代 这一概念,也就是说 永久代 是 HotSpot 的专属概念,例如: JRockit(Oracle)、J9(IBM) 中就没有 永久代

方法区永久代 的关系,和 Java 中的 接口 类似(接口 = 方法区;类 = 永久代),永久代 只是 方法区 这个 接口 的一个实现而已。

我们可以通过以下 JVM 参数来调节方法区的大小:

参数名描述
-XX:PermSize初始空间大小
-XX:MaxPermSize最大空间,超过这个值将会抛出 OutOfMemoryError 异常 java.lang.OutOfMemoryError: PermGen

误解:

网络上很多文章有这样一个说法:

通过设置 -XX:PermSize 和 -XX:MaxPermSize 可以调节 非堆(Non-Heap) 内存的大小 。

说可以调节 非堆(Non-heap) 内存的大小,其实是不准确的。严格说来这两个参数只对调节 永久代(HotSpot 对方法区的实现) 的大小有效。之所以这么说,是因为以下两点:

  1. 首先其他 JVM 厂商,在实现自家虚拟机的时候,不存在 永久代 这个概念( 永久代 只存在于 HotSpot 中),所以也就没有 -XX:PermSize 和 -XX:MaxPermSize 这两个参数。想让这两个参数在其他 非HotSpot 的虚拟机中起作用也就不可能了。
  2. 就算是同为 HotSpot JVM,在 1.8 版本中,由于 永久代元空间 取代,-XX:PermSize 和 -XX:MaxPermSize 这两个参数也同时被新的参数 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 所替代。

综上所述,我的理解是 -XX:PermSize 和 -XX:MaxPermSize 与 永久代 是一体的,同生同死的关系。

最后,还有一个比较有迷惑性的问题:

永久代 真的会像名字一样永远都不会进行垃圾收集吗?

答案是否定的。首先,HotSpot 设计团队之所以用 永生代 来实现 方法区,就是为了要复用HotSpot 的垃圾收集器,这样 GC分代收集 就可以扩展到方法区了。永久代不代表永远不进行垃圾收集,只是因为这个区域内的回收结果很难令人满意,尤其是类的卸载,条件特别的苛刻

4.3 元空间(Metaspace)

元空间 这个概念是在 JDK1.8 HotSpot JVM 中出现的,Ta 作为 方法区 的另一个 实现 取代了之前的 永久代

元空间永久代 的最大的不同是:元空间 并不在虚拟机中,Ta 使用的是 本地内存。因此,默认情况下,元空间 的大小仅受 本地内存限制,但我们可以通过对以下 JVM 参数的设置来调整 元空间 的大小:

参数名描述
-XX:MetaspaceSize初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时 GC 会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过 MaxMetaspaceSize 时,适当提高该值。
-XX:MaxMetaspaceSize最大空间,默认是没有限制的。

除了上面两个指定大小的参数以外,还有两个与 GC 相关的参数:

参数名描述
-XX:MinMetaspaceFreeRatio在 GC 之后,最小的 Metaspace 剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio在 GC 之后,最大的 Metaspace 剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cab5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值