写代码啦
JVM的GC算法
回复数(1) 浏览数(71)
早睡早起 03月12日 15:59 最后回复来自: 饥人谷茜茜 学霸评比参赛博客 博客
{{topic.upvote_count || 0}} 编辑 回复

GC分代假说

我们都知道,绝大多数对象都是朝生夕死。对于绝大多数GC算法而言都会遵循基本的分代假设。
它的结构如下所示,即

分代假说 分代假说

Young

此区域使用的GC算法为Mark and Copy,即没被回收的对象会被标记出来然后拷贝到幸存区。

Eden(TLAB 线程私有的分配缓存区,加快分配速度)
Survivor1

Survivor2

年轻代 年轻代

在年轻代,会触发Minor GC,年轻代的垃圾回收能回收掉70%--90%的内存。而幸存的对象会进入Survivor区中,并且每次Minor GC触发,不会被回收的对象会在Survivor区中交替复制,直到次数大于15次,这些对象会进入老年代。

Tenured(Old)

在老年代,使用的GC算法是Mark-Sweep-Compact,即没被回收的对象,会被标记出来,然后为了减少内存碎片,尽量的压缩成一块区域。
在老年代调用的使用的是Major GC区回收

PermGen/Metaspace

GC收集器

GC Mark

Stop The World (STW)
在GC开始之前,会先进行标记。标记的时候,要先把进程停止掉。所有的GC在工作的过程中,都要涉及到或多或少的STW,这是程序卡顿的原因。也是我们经常调优的目标。
safe point
当GC触发之前,先要运行到一个安全点,才能进行STW,通常而言,GC的停顿与堆大小无关,而是与活对象的大小有关。增加堆大小有时候反而会增加延迟。

我们下面介绍的垃圾回收器有三种Serial,Parallel,CMS,G1

垃圾收集算法 垃圾收集算法

Serial

serial回收算法如上图,分别应用在年轻代和老年代。基本和分代假说的说法一样,一根线程,从年轻代的标记复制,到STW,到老年代的标记清除整理。

Parallel

串行回收的并发版本,所作的事情是一样的。
我们可以从上图中看到的是,Parallel有三个回收器,即ParNew,Parallel Old,Parallel Scavenge,其中Parallel Old和Parallel Scavenge是搭配使用的。至于ParNew是因为CMS回收器只能回收老年代,它被开发出来用于和CMS搭配使用,回收年轻代。

CMS

GC回收算法对比 GC回收算法对比

我们可以看到左边是一个串行收集器,右边是CMS收集器,这两个对比起来,CMS的STW过程Initial Mark是一个比较短暂的过程,然后标记过程会和用户线程一起去执行,但是可能执行标记的不准确, 所以在之后的一段时间,又STW一会,并发去Remark标记。之后在清除的过程中,和用户线程并发的执行。

并且在CMS中,老年代只进行Mark-Sweep,而不进行Compact,主要用于低延时的系统。

G1

G1在Java9之后成为了默认的GC。如果想在Java8中使用它,可以加个参数Use G1 GC。

它横跨了年轻代和老年代,它制定的目标是软实时,比较大的堆内存(大于4G),可以设定目标(设定停顿时间,尽量达到)。

在G1的设计中,没有分代假说的存在了。它会将堆分成若干个等大的区域。

G1 G1

再回收的时候无需回收整个堆,而是回收一个Collection Set,即一个区域的集合。
在GC1中,有两种GC:

Fully young GC
Mixed GC
估计每个Region中的垃圾比例,优先回收垃圾多的Region。
{{topic.upvote_count || 0}}

GC分代假说

我们都知道,绝大多数对象都是朝生夕死。对于绝大多数GC算法而言都会遵循基本的分代假设。
它的结构如下所示,即

分代假说 分代假说

Young

此区域使用的GC算法为Mark and Copy,即没被回收的对象会被标记出来然后拷贝到幸存区。

Eden(TLAB 线程私有的分配缓存区,加快分配速度)
Survivor1

Survivor2

年轻代 年轻代

在年轻代,会触发Minor GC,年轻代的垃圾回收能回收掉70%--90%的内存。而幸存的对象会进入Survivor区中,并且每次Minor GC触发,不会被回收的对象会在Survivor区中交替复制,直到次数大于15次,这些对象会进入老年代。

Tenured(Old)

在老年代,使用的GC算法是Mark-Sweep-Compact,即没被回收的对象,会被标记出来,然后为了减少内存碎片,尽量的压缩成一块区域。
在老年代调用的使用的是Major GC区回收

PermGen/Metaspace

GC收集器

GC Mark

Stop The World (STW)
在GC开始之前,会先进行标记。标记的时候,要先把进程停止掉。所有的GC在工作的过程中,都要涉及到或多或少的STW,这是程序卡顿的原因。也是我们经常调优的目标。
safe point
当GC触发之前,先要运行到一个安全点,才能进行STW,通常而言,GC的停顿与堆大小无关,而是与活对象的大小有关。增加堆大小有时候反而会增加延迟。

我们下面介绍的垃圾回收器有三种Serial,Parallel,CMS,G1

垃圾收集算法 垃圾收集算法

Serial

serial回收算法如上图,分别应用在年轻代和老年代。基本和分代假说的说法一样,一根线程,从年轻代的标记复制,到STW,到老年代的标记清除整理。

Parallel

串行回收的并发版本,所作的事情是一样的。
我们可以从上图中看到的是,Parallel有三个回收器,即ParNew,Parallel Old,Parallel Scavenge,其中Parallel Old和Parallel Scavenge是搭配使用的。至于ParNew是因为CMS回收器只能回收老年代,它被开发出来用于和CMS搭配使用,回收年轻代。

CMS

GC回收算法对比 GC回收算法对比

我们可以看到左边是一个串行收集器,右边是CMS收集器,这两个对比起来,CMS的STW过程Initial Mark是一个比较短暂的过程,然后标记过程会和用户线程一起去执行,但是可能执行标记的不准确, 所以在之后的一段时间,又STW一会,并发去Remark标记。之后在清除的过程中,和用户线程并发的执行。

并且在CMS中,老年代只进行Mark-Sweep,而不进行Compact,主要用于低延时的系统。

G1

G1在Java9之后成为了默认的GC。如果想在Java8中使用它,可以加个参数Use G1 GC。

它横跨了年轻代和老年代,它制定的目标是软实时,比较大的堆内存(大于4G),可以设定目标(设定停顿时间,尽量达到)。

在G1的设计中,没有分代假说的存在了。它会将堆分成若干个等大的区域。

G1 G1

再回收的时候无需回收整个堆,而是回收一个Collection Set,即一个区域的集合。
在GC1中,有两种GC:

Fully young GC
Mixed GC
估计每个Region中的垃圾比例,优先回收垃圾多的Region。
71
回复 编辑