搞定JVM系列(四):CMS垃圾收集器和G1垃圾收集器

对于JVM的垃圾收集器而言,CMS和G1是重点,在内存回收领域都有重要意义。

CMS垃圾收集器

CMS垃圾回收器的全称是Concurrent Mark-Sweep Collector,使用的是并发收集,收集算法为Mark-Sweep,为了低延迟而生,是老年代的垃圾收集器。特点是低延迟并且会有浮动垃圾。一般情况下会有ParNew来配合执行(默认情况下也是ParNew),ParNew也是使用并行的算法来执行年轻代的回收。

一、CMS堆结构

CMS的堆结构化为三个部分:年轻代、年老代和永久代(或元数据区)。

1、新生代

新生区是类的诞生、成长、消亡的区域,其中新生代又分为两部分:伊甸区(Eden space)和幸存者区(Survivor pace)。所有的类都是在Eden 区被new出来的。Survivor区又分为两个:0区(Survivor 0 space)和1区(Survivor 1 space)。

2、老年代

老年代用于保存从新生代筛选出来的 JAVA 对象,一般池对象都在这个区域活跃。

3、永久代(已在JDK1.8中去除,合并入元空间)

永久代存储区是一个常驻内存区域,用于存放JDK自身所携带的 Class,Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。

二、CMS垃圾回收过程

1、CMS的Yong GC(年轻代收集)

当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园进行垃圾回收(Minor GC),将伊甸园中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。那如果1去也满了呢?再移动到养老区。若养老区也满了,那么这个时候将产生Major GC(FullGCC),进行养老区的内存清理。若养老区执行Full GC 之后发现依然无法进行对象的保存,就会产生OOM异常“OutOfMemoryError”。

2、CMS的年老代GC

CMS(Concurrent Mark Sweep)收集器是一种以最短回收停顿时间为目标的收集器。使用并发-标记-清理。CMS收集器在收集老年代的时候分为以下几个阶段:初始标记、并发标记、预处理、最终标记、并发清除、并发重置。重点是以下4步:

a、初始标记
这个阶段需要STW(stop the world),仅仅只标记GC Roots能直接关联到的对象,速度很快
b、并发标记
进行GC Roots Tracing(追踪)的过程,从GC Roots开始从堆中对象进行可达性分析,找出存活对象
c、重新标记
这个阶段需要STW(stop the world),为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,停顿时间:初始标记<重新标记<并发标记;
d、并发清除
对可回收区域进行清理,可与用户线程一起并发执行。

三、特点

1、优点:

并发收集,低延迟。

2、缺点:

  • 对CPU资源非常敏感,会占用一部分CPU资源导致应用程序变慢,总吞吐量变低。
  • 无法处理浮动垃圾,可能出现“Concurrent Mode fail”失败导致一次full GC的产生。
  • “标记-清除”算法导致收集结束产生大量的空间碎片,老年代空间会随着应用时长被逐步耗尽,最后将不得不通过担保机制对堆内存进行压缩。

 

G1垃圾收集器

G1(Garbage First)是一款面向服务端应用的垃圾回收器,目标是多处理器机器、大内存机器,它高度符合垃圾收集暂停时间短的目标,同时实现高吞吐量。SUN公司在JDK1.7中提出,是JDK9的默认收集器。

一、G1堆结构

老的垃圾收集器都把堆结构化为三个部分:年轻代、年老代和永久代(或元数据区)。而G1垃圾收集器采用了另外一种完全不同的方式组织堆内存,堆内存被划分为很多个固定大小的内存块(Region),每个Region是逻辑连续的一段内存。Region被分成了eden、survivor和old区。除此之外,其实还有第四类——大Region,标记为H(巨型对象),此部分区域用来存放超过标准Region大小的50%或者更大的对象,此部分在内存中是连续的当。

Regin大小区间只能是1M、2M、4M、8M、16M和32M,总之是2的幂次方,可以通过-XX:G1HeapRegionSize参数指定大小。

二、G1垃圾回收过程

1、G1的Yong GC(年轻代收集)

如下图,堆空间被分割成大约2000个区域,最小1M,最大32M,蓝色区域保持年老代对象,绿色区域保持年轻代对象。
活跃对象会被疏散(复制、移动)到一个或多个survivor区域。如果达到晋升总阈值,对象会晋升到年老代区域。

发生young GC 的时候,会发生STW 的停顿。survivor 和Eden Region会为下次young GC进行计算,计算过程中会结合设置的一些参数(如:-XX:MaxGCPauseMillis=10 -XX:GCPauseIntervalMillis=200等)。这使重调区域大小变得很容易,按需把它们调大或调小。

关于G1的年轻代回收做以下总结:

  • 堆空间是一块单独的内存空间被分割成多个区域。
  • 年轻代内存是由一组非连续的区域组成。这使得需要重调大小变得容易。
  • 年轻代垃圾回收是stop the world事件,所有应用线程都会因此操作暂停。
  • 年轻代垃圾收集使用多线程并行回收。
  • 活跃对象被复制到新的Survivor区或者年老代区域。

2、G1的Old GC(年老代收集)

年老代收集大体分这几个步骤:

  • 初始标记,此过程会发生STW,标记指向旧生代对象的suvivor Region。
  • 根区扫描,此过程与应用并发执行,扫描指向旧生代对象的suvivor Region,但是扫描必须在young GC之前完成。
  • 并发标记,此过程与应用并发执行,查找整个堆上存活的对象,此过程可以被young GC 打断
  • 重新标记,此过程会发生STW,此过程中采用起始快照算法(snapshot-at-the-beginning,SATB),该算法比CMS的收集器算法快许多。
  • 清除回收,此过程部分阶段会发生STW。1.统计存活和完全空闲的region(发生STW)2.修改标记列表(发生STW)3.重置空闲Region并标记到空闲列表上(与应用并发)
  • 复制,此过程发生STW。复制存活的对象到未使用的Region上,此过程在youngGC中也会发生。youngGC 发生日志中标记为GC pause (young),young GC和old GC同时发生的时候,日志中标记为GC Pause (mixed)。

a、初识标记

年轻代垃圾收集肩负着活跃对象初始标记的任务。在日志文件中被标为GC pause (young)(inital-mark) 。

b、并发标记阶段

如果发现空区域(“X”标示的),在重新标记阶段它们会被马上清除掉。当然,决定活性的审计信息也在此时被计算。

c、重新标记阶段

空的区域被清除和回收掉。所有区域的活性在此时计算。 

d、复制/清理阶段

G1选择活性最低的区域,这些区域能够以最快的速度回收。然后这些区域会在年轻代垃圾回收过程中被回收。在日志中被指示为[GC pause (mixed)]。所以年轻代和年老代在同一时间被回收。 

e、复制/清理阶段之后

年老代垃圾回收总结:

1、并发标记阶段

  • 当应用运行时,并发的计算活性信
  • 在疏散暂停期间,活性信息鉴定哪些区被最好的回收
  • 没有像CMS一样的清除操作

2、重新标记阶段

  • 使用比在CMS中使用的算法更快的Snapshot-at-the-Beginning(SATB)算法
  • 完全空的区域会被回收掉

3、复制/清理阶段

  • 年轻代和年老代被同时回收
  • 年老代区域基于它们的活性被选择

三、特点

1、并行与并发

G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短‘stop the world’停顿的时间,部分其他收集器需要停顿java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java用户线程继续执行。

2、分代收集

能采取不同的方式去处理新创建的对象、已经存活一段时间的对象,或者已经熬过多次gc的对象。

3、空间整合

G1从整体来看是基于“标记-整理”算法实现,从局部上基于“复制算法”实现。这两种算法都不会产生空间碎片。

4、可预测的停顿

降低停顿时间是G1和CMS共同关注点,但是G1还能建立可以预测的时间停顿模型,能让使用者明确指定一个长度时间为M毫秒时间段内,垃圾收集时间不超过N毫秒。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值