垃圾收集器主要分为两大类:分区收集器和分代收集器。分代收集器的代表是CMS,分区收集器的代表是G1和和ZGC。
分代收集器
CMS
CMS收集器是第一个关注GC停顿时间(stw时间)的收集器,采用“标记-清除”算法,之前的垃圾收集器,要么是串行的垃圾回收方式,要么只关注系统吞吐量。
stw是 stop the world,也就是当垃圾收集的时候,用户线程只能等着,这部分的时间就是stw。
CMS使用了可达性分析算法,并进行改进,使之能够进行用户线程和垃圾收集线程并发,从而极大地降低了系统响应时间。
那CMS到底是如何进行的,如何使之能并发?
CMS的步骤
- 初始标记
- 并发标记
- 重新标记
- 并发清除
初始标记
初始标记就是只标记与GCRoot有直接引用关系的对象。
看图:
可以从图中看到,这里只标记粉色的对象。并不需要做全盘的扫描,所以速度很快。
并发标记
并发标记的意思是对于初始标记所标记过的节点,进行整个引用链的扫描。并且因为对于整个引用链的扫描很耗费时间,所以这个部分让用户进程和垃圾收集进程并发进行,不必stw 。这也是CMS能极大降低 GC 停顿时间的核心原因。
但是我们试想一下,会不会发生在垃圾手机的过程中,节点的引用新增或者删除?当然有可能发生!!所以我们需要第二次重新标记。
重新标记
这个过程是对并发标记的产生的问题进行校正。因为要校正,所以必须要准确,哪怕耗费时间。所以这个过程一定要stw,否则还是会产生并发标记的问题。
并发清除
的是将标记为垃圾的对象进行清除,该阶段不需要「Stop the World」。 在这个阶段,垃圾回收线程与用户线程可以并发执行,因此并不影响用户的响应时间。
CMS优缺点
CMS 的优点是:并发收集、低停顿。但缺点也很明显:
①、对 CPU 资源非常敏感,因此在 CPU 资源紧张的情况下,CMS 的性能会大打折扣。
默认情况下,CMS 启用的垃圾回收线程数是(CPU数量 + 3)/4
,当 CPU 数量很大时,启用的垃圾回收线程数占比就越小。但如果 CPU 数量很小,例如只有 2 个 CPU,垃圾回收线程占用就达到了 50%,这极大地降低系统的吞吐量,无法接受。
②、CMS 采用的是「标记-清除」算法,会产生大量的内存碎片,导致空间不连续,当出现大对象无法找到连续的内存空间时,就会触发一次 Full GC,这会导致系统的停顿时间变长。
③、CMS 无法处理浮动垃圾,当 CMS 在进行垃圾回收的时候,应用程序还在不断地产生垃圾,这些垃圾会在 CMS 垃圾回收结束之后产生,这些垃圾就是浮动垃圾,CMS 无法处理这些浮动垃圾,只能在下一次 GC 时清理掉。