Serial 收集器
单线程收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,最重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。“stop the world”这个名字也许听起来挺酷,但这项工作实际上是由虚拟机在后台自动发起和自动完成的,在用户不可见的情况下把用户正常工作的线程全部停掉,这对很多应用来说都是难以承受的。读者不妨试想一下,要是你的计算机每运行一个小时就会暂停相应5分钟,你会有什么样的心情?
- 优点
简单高效(与其他收集器的单线程比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。
ParNew 收集器
ParNew收集器其实就是Serial收集器的多线程版本。除了使用多条线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一致。
ParNew 收集器除了多线程收集之外,其他与Serial收集器相比并没有太多创新之处,但它却是许多运行在Server模式下的虚拟机中首选的新生代收集器,其中有一个与性能无关,但最重要的原因是,除了Serial收集器外,目前只有它能与CMS收集器配合工作。ParNew收集器也是使用-XX:+UseConcMarkSweepGC选项后的默认新生代收集器。
CMS 收集器
CMS(Concurrent Mark Sweep) 收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的 java 应用几种在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
从名字(包含“Mark Sweep”)上就可以看出,CMS收集器是基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为4个步骤,包括:
初始标记(CMS initial mark)
并发标记 (CMS concurrent mark)
重新标记(CMS remark)
-
并发清除(CMS concurrent sweep)
其中,初始标记、并发标记这两个步骤仍然需要“Stop The World”。初始标记仅仅是标记一下GC Roots能直接关联到的对象,速度很开,并发标记阶段就是进行GC Roots Tracing 的过程,而重新标记则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的暂停时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以和用户线程一起工作,因此,从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
缺点
- CMS收集器对CPU资源非常敏感
- CMS收集器无法处理浮动垃圾
- CMS是一款基于“标记-清除”算法实现的收集器,会产生大量空间碎片。空间碎片过多时,将会给大对象分配带来很大麻烦,往往出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前出发一次Full GC。为了解决这个问题,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数,用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间不得不变长。虚拟机设计者还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,表示每次进入Full GC时都要进行碎片整理)。