持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
1.常用的垃圾回收器
目前的垃圾回收器总共十种:
其中serial和serial old有stop the world 简称stw,即停止其他业务线程,只进行垃圾回收线程的执行;并且是单线程的。
serial是单线程的,如下:
ps和po是多线程的,如下图:
ParNew与ps、po区别不大,也是并行的,并且也是stw的,只是ParNew能搭配CMS进行垃圾回收
CMS如下:(初始标记和重新标记是STW的)
-
初始标记是找到根对象
-
并发标记:这个过程业务线程和垃圾回收线程可以同事执行
在这个过程中,使用三色标记算法,但是存在这样一种可能:
- 三色:黑色(全部子引用对象都遍历过)、灰色(正在遍历,只遍历了部分子引用对象)、白色(还未遍历过其子引用对象)
- 当我们正要遍历灰色对象的子引用时(子引用还是白色)这个时候我们突然切断灰色对象与子引用之间的引用,然后让这个白色对象成为其它标记为了黑色的对象的子对象,这个时候可能会造成误回收。
- 所以我们会存在重复标记
-
重复标记:这个过程是STW的,即让其他业务线程停止一小会,进行垃圾回收,当然这个过程肯定是要比serial和serial old一开始就进行STW要快的。
-
最后就是并发的清理垃圾对象
G1 在逻辑上分区,在物理上是不分区的,物理上分成了一个一个的小Region
G1,采用了concurrent marking cycle:
- 初始标记(Initial Marking):标记一下GC Roots能直接关联到的对象,伴随着一次普通的Young GC发生,并修改NTAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,此阶段是stop-the-world操作。 根区间扫描,标记所有幸存者区间的对象引用,扫描 Survivor到老年代的引用,该阶段必须在下一次Young GC 发生前结束。
- 并发标记(Concurrent Marking):是从GC Roots开始堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行,该阶段可以被Young GC中断。
- 最终标记(Final Marking):是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,此阶段是stop-the-world操作,使用snapshot-at-the-beginning (SATB) 算法。
- 筛选回收(Live Data Counting and Evacuation):首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,回收没有存活对象的Region并加入可用Region队列。这个阶段也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。
G1在Java9中成了JVM中默认的垃圾收集器。
ZGC采用了颜色指针,如下:
ZGC在Java11开始崭露头角,在Java15转正,成为了JVM默认的垃圾回收器。
全部总结如下: