第一次如何记住繁杂的垃圾收集器

第一次如何记住繁杂的垃圾收集器

首先在学习垃圾收集器之前,你一定要知道JVM内存模型和常见的垃圾回收算法。

第一次如何记住繁杂的垃圾收集器_第1张图片

连线代表相互之间可以配合使用,G1则在新生代和老年代都使用;

简单介绍

垃圾收集器可以分为串行(Ser)并行(par)、**响应时间优先(CMS)**来记。

  • 串行回收器:Serial、Serial old
  • 并行回收器:ParNew、Parallel Scavenge、Parallel old
  • 并发回收器:CMS、G11

年轻代

  • 最早出现的是单线程的 — > Serial
  • 并行的 ----- > ParNew
  • 吞吐量优先的(不关注单次GC时间) ----- > Parallel Scavenge(一般客户端)

老年代

  • Serial Old ---- 和年轻代的 Serial 搭配使用
  • CMS(G1出现之前广泛使用) ---- 年轻代ParNew
  • Parallel Old ---- 年轻代Parallel Scavenge

年轻代的Minor GC一般时间比较短,我们更关注时间较长的老年代回收;

Serial Old串行Parallel Old关注吞吐率的故它们单次执行GC的时间可能过长;而CMS则关注单次GC的时间;

CMS GC过程

CMS收集器是一种以获取最短回收停顿时间为目标的收集器;(在GC过程中,一般用户线程都会有短暂停止,也就是回收时用户线程要停止。CMS的出现是第一个真正意义上实现垃圾收集线程和用户线程同时工作)

我们来看看它的过程:

  1. 初次标记 : 时间很短,只是标记一些GC Roots能直接关联的对象。(需要Stop the World也就是用户线程不能工作
  2. 并发标记 : 标记所有的对象,时间较长, 用户线程未停顿,故可能会产生新的要清理的对象,所有我们来到重新标记。
  3. 重新标记 : 修正第二步导致标记变动的对象的标记记录。 需要Stop the World (时间比第一步稍长,但是远比第二步短,所以总共来说并没有Stop the World 特别长的时间,用户体验nice)
  4. 并发清除: 清除被标记的对象 — 采用标记清除算法 (用户引用的对象还在原来的位置,故可以并发)。

在老年代Serial Old和Parallel Old都是采用的标记整理算法(不会产生内存碎片)

带并发两个字的当然代表其收集器线程和用户线程同时工作,其他两个则需要Stop the world

CMS缺点

对于cpu核数低的服务器不友好

因为在并发标记和并发清除阶段均是并发执行,CMS默认启动的回收线程数为(cpu核数 + 3) / 4,对于那些核数低于4的战五渣服务器及其不友好;

无法处理浮动垃圾

什么是浮动垃圾?

就是并发标记和并发清除阶段,回收线程和用户线程同时运行时产生的垃圾对象,并且这些垃圾在标记结束以后,CMS无法在档次收集中处理它们只能下一次垃圾收集时再清理;

因为无法处理浮动垃圾,故在垃圾收集之前,不能等老年区满了再收集(会产生浮动垃圾),故要预留一部分空间供并发收集时使用,到底预留多少空间,就是真正难办的地方,预留太多了GC容易被激活,预留太少的话可能不够并发收集时产生的新垃圾,这样就会出现并发失败的情况

并发失败后 : 启动后备预案,冻结用户线程,临时用Serial Old来重新收集,这样停顿时间就很长了。故预留多少要根据实际情况来定

产生内存碎片

前面提到CMS并发清除是用的 标记-清除法,那么肯定会产生内存碎片嘛。

可以通过设置 -XX: CMSFullGCsBeforeCompaction(jdk9已废弃)使其在不整理空间的Full GC后,下一次进入Full GC前会先进行碎片整理

G1

地位:垃圾收集器里程碑式的成果;

G1是面向堆内存任何部分进行回收的,内存中哪个地方垃圾最多就进行回收 ---- Mixed GC模式;

在以前,我们一般新生区是内存是一段连续的,老年区也是连续的,而G1开创了一种Region的堆内存布局,分成多个大小相等的独立区域(Region) ,每个Region可能是Eden、Survivor或者老年代空间

并且还有一个特殊的Humongous区域存储大对象(超过Region容量的一半),一般一个Region为1M ~ 32 M

Region内存布局:

第一次如何记住繁杂的垃圾收集器_第2张图片

每一个Region维护了一个记忆集(key - value形式)解决跨Region引用问题 ---- Rset

每个Region维护两个TAMS指针用来保证收集线程和用户线程互不干扰的运行

G1 GC过程

  1. 初始标记:标记GC Root 和Root Region(GC Root所在的Region); STW(Stop the world)
  2. 将Root Region去扫描old区中的Rset是否有Root Region,将其标识 STW
  3. 并发标记: 只需遍历被第二步标记的即可(遍历范围缩小) — 同CMS。
  4. 重新标记 : 同CMS,只不过用的SATB(三色标记)STW
  5. 清理(复制清理) : 只选出垃圾较多的地方进行清理。STW

小结

  1. G1只标记了Rset(跨代引用)和GC Root的Region进行遍历,而CMS是所有对象进行遍历;
  2. STAB原始快照搜索算法进行重新标记
  3. 将各个Region回收价值进行排序,根据用户设置的期望停顿来制定回收计划(并不是全部清除);

第一次学习垃圾收集器,有记录错误的地方欢迎指出;

你可能感兴趣的:(JAVA)