小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
并发的可达性分析
当且仅当以下两个条件同时满足时,不该回收的对象会被误回收,即白色对象没有被标记为黑色
- 新增了一条或多条从黑色对象到白色对象的新引用。
- 删除了全部灰色对象到该白色对象的直接或间接引用。 有两种方式解决这个问题
增量更新
破坏第一个条件。新增黑色对象到白色对象的引用时,将这个新插入的引用记录下来,等待并发扫描结束之后,再根据记录的引用关系重新进行一次扫描,即当新增一条黑色到白色对象的引用后,黑色对象降级为灰色对象。
原始快照(SATB)
破坏第二个条件。删除灰色对象指向白色对象的引用关系时,将删除的引用记录下来,在并发扫描结束后,再根据记录的引用关系重新进行一次扫描。即只按照刚开始扫描那一刻的对象图快照进行搜索。
CMS的收集过程
CMS(Concurrent Mark Sweep)收集器的目标追求“获取最短时间”。其过程分为四个步骤
- 初始标记:标记出GC Roots,该过程STW.
- 并发标记:从GC Roots开始进行可达性分析,该过程较长与用户线程并行。
- 重新标记:进行增量更新,防止并发标记过程中将黑色对象误标记为白色,该过程STW。
- 并发清除:清理掉标记为死亡的对象,与用户线程并行。
优点
并发收集、低停顿
CMS的缺点
对处理器资源敏感
在并发阶段会因为占用一部分线程,即处理器的计算能力,导致应用程序变慢。
无法处理浮动垃圾
CMS垃圾收集器是并发标记的,无法处理此时用户线程产生的垃圾,这部分垃圾被称为“浮动垃圾”,只能在下次垃圾收集中回收。并且由于垃圾收集阶段用户线程还在运行,必须预留足够内存空间提供给用户线程使用,这就要求不能等待老年代几乎完全被填满才进行收集,需要留一部分空间提供给并发收集阶段的用户线程使用。
可以通过-XX: CMSInitiatingOccu-pancyFraction的值来提高垃圾收集的触发百分比,降低回收频率,在JDK6中这个值默认为92%。但如果预留的内存无法满足分配新对象的需要,就会出现“并发失败”问题,这时只能冻结用户线程的执行,临时启用Serial Old收集器进行老年代的垃圾收集,这样停顿时间会变得很长。
需要整理标记-清除算法带来的空间碎片
由于CMS基于“标记-清除”算法实现,收集结束后有大量空间碎片产生,分配大对象可能找不到连续的内存空间而进行Full GC。为了解决这个问题CMS默认在Full GC前整理合并内存碎片,由于必须移动存货对象,因此不能并发,停顿时间变长。另外可以指定在N次没有整理碎片的Full GC后进行一次碎片整理(JDK9中被废弃)。