JVM GC 分析

in 代码 with 0 comment

From: https://www.cnblogs.com/yy3b2007com/p/10975870.html

垃圾

了解 JVM GC 原理非常重要,对于系统调优非常有用。如果一个系统频繁发生 FULL GC,那么会造成系统响应卡顿,更严重的时候会导致系统崩溃。

JVM 的内存空间

JVM 的内存空间,从大的层面上来分析包含:新生代空间 (Young) 和老年代空间(Old)。新生代空间(Young)又被分为 2 个部分(Eden 区域、Survivous 区域)和 3 个板块(1 个 Eden 区域和 2 个 Survivous 区域)

GC-heap-1

下边来看下具体每部分都是用来干什么的。

1)Eden(伊甸园)区域: 用来存放使用 new 或者 newInstance 等方式创建的对象,默认这些对象都是存放在 Eden 区,除非这个对象太大,或者超出了设定的阈值 - XX:PretenureSizeThresold,这样的对象会被直接分配到 Old 区域。

2)2 个 Survivous(幸存)区域: 一般称为 S0,S1,理论上他们一样大。

下边将会讲解它们如何工作的。

第一次 GC:

在不断创建对象的过程中,当 Eden 区域被占满,此时会开始做 Young GC 也叫 Minor GC

1)第一次 GC 时 Survivous 中 S0 区和 S1 区都为空,将其中一个作为 To Survivous(用来存储 Eden 区域执行 GC 后不能被回收的对象)。比如:将 S0 作为 To Survivous,则 S1 为 From Survivous。

2)将 Eden 区域经过 GC 不能被回收的对象存储到 To Survivous(S0)区域(此时 Eden 区域的内存会在垃圾回收的过程中全部释放),但如果 To Survivous(S0)被占满了,Eden 中剩下不能被回收对象只能存放到 Old 区域。

3)将 Eden 区域空间清空,此时 From Survivous 区域(S1)也是空的。

4)S0 与 S1 互相切换标签,S0 为 From Survivous,S1 为 To Survivous。

GC-heap-2

 

第二次 GC:

当第二次 Eden 区域被占满时,此时开始做 GC

1)将 Eden 和 From Survivous(S0)中经过 GC 未被回收的对象迁移到 To Survivous(S1),如果 To Survious(S1)区放不下,将剩下的不能回收对象放入 Old 区域;

2)将 Eden 区域空间和 From Survivous(S0)区域空间清空;

3)S0 与 S1 互相切换标签,S0 为 To Survivous,S1 为 From Survivous。

GC-heap-3

 

第三次,第四次一次类推,始终保证 S0 和 S1 有一个空的,用来存储临时对象,用于交换空间的目的。反反复复多次没有被淘汰的对象,将会被放入 Old 区域中,默认 15 次(由参数 --XX:MaxTenuringThreshold=15 决定)。

MG 动画图解

动画文件存放在加载比较慢,请耐心等待

GC 中相关问题

问题 1:怎么定义活着的对象?

从根引用开始,对象的内部属性可能也是引用,只要能级联到的都被认为是活着的对象。

问题 2:什么是根?

本地变量引用,操作数栈引用,PC 寄存器,本地方法栈引用等这些都是根。

问题 3:对象进入 Old 区域有什么坏处?

Old 区域一般称为老年代,老年代与新生代不一样。新生代,我们可以认为存活下来的对象很少,而老年代则相反,存活下来的对象很多,所以 JVM 的堆内存,才是我们通常关注的主战场,因为这里面活着的对象非常多,所以发生一次 FULL GC,来找出来所有存活的对象是非常耗时的,因此,我们应该避免 FULL GC 的发生。

问题 4:S0 和 S1 一般多大,靠什么参数来控制,有什么变化?

一般来说很小,我们大概知道它与 Young 差不多相差一倍的比例,设置的参数主要有两个:

-XX:SurvivorRatio=8
-XX:InitialSurvivorRatio=8

第一个参数(-XX:SurvivorRatio) 是 Eden 和 Survivous 区域比重(注意 Survivous 一般包含两个区域 S0 和 S1,这里是一个 Survivous 的大小)。如果将 - XX:SurvivorRatio=8 设置为 8,则说明 Eden 区域是一个 Survivous 区的 8 倍,换句话说 S0 或 S1 空间是整个 Young 空间的 1/10,剩余的 8/10 由 Eden 区域来使用。

第二个参数(-XX:InitialSurvivorRatio) 是 Young/S0 的比值,当其设置为 8 时,表示 S0 或 S1 占整个 Young 空间的 1/8(或 12.5%)。

问题 5:一个对象每次 Minor GC 时,活着的对象都会在 S0 和 S1 区域转移,讲过 MInor GC 多少次后,会进入 Old 区域呢?

默认是 15 次(CMS 是 6),参数设置

--XX:MaxTenuringThreshold=15

,计数器会在对象的头部记录它的交换次数。

问题 6:为什么发生 FULL GC 会带来很大的危害?

在发生 FULL GC 的时候,意味着 JVM 会安全的暂停所有正在执行的线程(Stop The World),来回收内存空间,在这个时间内,所有除了回收垃圾的线程外,其他有关 JAVA 的程序,代码都会静止,反映到系统上,就会出现系统响应大幅度变慢,卡机等状态。