• JVM HotSpot 之 内存结构演进过程


    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 剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
  • 相关阅读:
    Kerberos (四) --------- 安全集群使用说明
    数据库的基本操作(5)
    嵌入式学习笔记(39)蜂鸣器和PWM定时器编程实践
    基于深度学习的水果识别系统
    ffmpeg图片转YUV格式
    不标准的 json 格式的字符串如何转为标准的(json字符串属性名不带双引号如何转
    Npm Install Docusaurus Demo【npm 安装 docusaurus 实践 】
    pytorch 手写数字识别例子
    CSS相关
    C++中栈与堆数据存取情况
  • 原文地址:https://blog.csdn.net/yangchao1125/article/details/126505042