G1学习

之所以单独写一篇是觉得 深入理解JVM虚拟机这本书,对G1细节讲的太少,而且在网上查的资料看起来也很模糊,甚至很有误导性,所以整理了下,但说实话我还是没有理解这个G1完整的过程,将来还是需要慢慢理解整理。

内存分配描述

G1 的内存不再是像以前一样的连续的内存分布,而是非连续的内存分布
g1收集器内存分布
每一块是一个region,可以通过-XX:G1HeapRegionSize指定大小,只能是2的幂等次,
H表示的是巨型对象,巨型对象默认是分配在老年区,但是如果是短期的,那么会对老年区造成影响,所以G1划分了H区,如果一个H区放不下,那么会分配连续的空间存放

GC 模式

共有三种GC模式:

  1. young gc
  2. mixed gc
    分为两个部分:
    1. global concurrent marking
    2. 混合垃圾回收 STW
  3. full gc

young gc一般是当所有的eden region都被耗尽,就触发一次young gc,执行完一次之后,对象被拷贝survivor 或者old

mixed gc 并不是一个old gc,这是重点, 他会回收整个的young,和部分的old,当老年代达到了内存的阙值时触发

young gc

STW

阶段分为:

  1. 根扫描, 静态和本地对象被扫描
  2. 更新RS, 处理dirty card队列更新RS
  3. 处理RS, 检测从年轻代指向年老代的对象
  4. 对象拷贝,复制到survivor 和old
  5. 处理引用队列,软引用,弱引用,虚引用处理

其实不是很理解步骤2,3

这里思考一个问题,如果要只收集young, 但young 和old肯定是会有互相引用,难道要扫描全部内存?G1使用了remember set (rset) ,每个region有一个rset,记录谁引用了这块region(point-in),这个概念在其他收集器中也有体现(资料说是CMS,但我觉得只要分代收集就要用这个),但在之前rset记录的是老年代引用了哪些新生代对象(point-out),所以直接扫描这块,就不用扫描全部,

在G1中使用的是ponit-in,记录的是谁引用了这块,因为分区太多,这个rset只记录年老代到新生代的引用,因为每次GC eden都被扫描,

这就又产生一个问题,一个region有很多对象,记录可能会很多 ,所以又产生一个概念,cardTable, 其实就是把一个分区划分为多个区域,rset只记录指向哪个区域,而不是精确到对象

rset和cardTable

mixed gc

选定所有年轻代里的Region,外加根据global concurrent marking统计得出收集收益高的若干老年代Region。在用户指定的开销目标范围内尽可能选择收益高的老年代Region

分为两个步骤:

  1. 全局并发标记(global concurrent marking)
  2. 混合垃圾回收

global concurrent marking主要为mix gc提供标记服务,并不是必须环节,分为五个步骤:

  1. 初始标记(initial mark,STW)
    stop-the-world,它伴随着一次普通的 Young GC 发生,然后对 Survivor 区(root region)进行标记,因为该区可能存在对老年代的引用,因为 Young GC 是需要 stop-the-world 的,所以并发标记直接重用这个阶段
  2. 根区域扫描(root region scan)
    扫描 Survivor 到老年代的引用,该阶段必须在下一次 Young GC 发生前结束
  3. 并发标记(Concurrent Marking)
    寻找整个堆的存活对象,该阶段可以被 Young GC 中断
  4. 最终标记(Remark,STW)
    stop-the-world,完成最后的存活对象标记。使用了比 CMS 收集器更加高效的 snapshot-at-the-beginning (SATB) 算法
  5. 清除垃圾(Cleanup,STW)
    清除空Region,即没有存活对象的region,所以这步不能看作mixgc的清理阶段

并发标记结束后是混合垃圾回收周期,不仅进行年轻代垃圾收集,而且回收之前标记出来的老年代的垃圾最多的部分区块。

混合垃圾回收周期会持续进行,直到几乎所有的被标记出来的分区(垃圾占比大的分区)都得到回收,然后恢复到常规的年轻代垃圾收集,最终再次启动并发标记。

所以看起来young gc 和mix gc并不是互斥进行,可以说是同时在进行。

full gc

什么情况会触发full gc(STW收集):

  1. concurrent mode failure:并发模式失败,CMS 收集器也有同样的概念。G1 并发标记期间,如果在标记结束前,老年代被填满,G1 会放弃标记
  2. 晋升失败:并发周期结束后,是混合垃圾回收周期,伴随着年轻代垃圾收集,进行清理老年代空间,如果这个时候清理的速度小于消耗的速度,导致老年代不够用,那么会发生晋升失败
  3. 疏散失败:年轻代垃圾收集的时候,如果 Survivor 和 Old 区没有足够的空间容纳所有的存活对象。这种情况肯定是非常致命的,因为基本上已经没有多少空间可以用了,这个时候会触发 Full GC 也是很合理的。

三色标记法

TODO 待补全

常用参数

TODO 待补全

参考:

http://blog.jobbole.com/109170/
http://ifeve.com/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3g1%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%99%A8/
https://tech.meituan.com/2016/09/23/g1.html 讲的最好
https://juejin.im/entry/5af0832c51882567244deb44