首先G1垃圾回收器和分代回收是从不同角度看待垃圾回收
分代回收是根据对象的特点分为新生代(低情商:早死鬼),老年代(低情商:老不死的东西)
G1垃圾回收器是根据对象存放的区域进行划分:死鬼聚集地 和 活人聚集地(注意,这里不能理解成分类,只是对区域垃圾不同程度的称呼,就像每个男人都好色,但只有最好色的那一批人才被称为色魔)
这两种角度互不冲突,可以相互进行结合
而对这两种角度进行结合的回收器就是G1垃圾回收器
分代回收的思想是怎么样的,我上一篇文章已经讲过了。这里不在赘述
这里重点讲讲:G1的分区域思想是如何实现的 ,以及这份思想如何与分代回收结合的
1,分区域思想的实现:
首先G1回收器将堆内存划分为一块块region,然后我们需要判断那些区域是“死鬼聚集地”,那些是“活人聚集地”, G1回收器内部维护了一个优先级列表
优先级越高的地方越“死鬼”。 G1根据用户制定的参数消灭一些死鬼聚集地,
这里你可能会有疑问G1是如何维护这个优先级列表呢?它是如何知道一个region内死鬼的多少呢?
答:通过并发标记(下文在讲)
2,如何把分代和分区域结合起来:
这里我们直接来看G1回收器的工作流程就懂了:
大部分书会直接讲Mixed GC部分,但那不是G1回收的全部
这里的youngGC其实就是minorGC换了个马甲,因为G1分区域了,导致实现上有些不一样,但实际上还是那一套。
我们看到G1大部分时间可能还是在youngGC处理新生代,而不是一直在MixedGC,它只有达到
|
这个标准才会MixedGC(实际上不是严格意义上MixedGC,但这里这样理解是可以的,之后会解释) 这个InitiatingHeapOccupancyPercent
参数有很多文章所示老年代占堆内存的大小
但官方给的定义是
设置触发标记周期的 Java 堆占用阈值。默认占用是整个 Java 堆的 45%。 |
详细可查https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html
我们再来讲讲这里的MixedGC部分是如何实现的:
我们看到MixedGC的主要分为四个步骤:
1,初始标记:简单标记一下与GCRoot直接关联的对象
2,并发标记:对GCRoot开始堆中对象进行可达性分析,扫描整个堆的对象图(这样哪里有多少垃圾不就一目了然吗,通过这一步维护优先级列表)。
3,最终标记:处理并发标记阶段遗留下的少量SATB记录。(这部分属于SATB算法的知识,看不懂没关系)
4,筛选回收:更新一下优先级列表(毕竟最终标记部分可能有修改)根据优先级列表 处理垃圾区域 处理方式是:把垃圾区域中存活对象复制放到空的region中,把原来的垃圾region清空。
但实际上:初始标记阶段可以由YoungGC来顺手完成不是吗?
所以我之前说的到阈值才进行 MixedGC实际上是不严谨的,某种意义上YoungGC就已经开始MixedGC了。