常见的垃圾收集器

垃圾收集器是内存回收的具体实现,不同的厂商、不同版本的虚拟机所提空的垃圾收集器可能会有很大差别,并且一般都会提供参数供用户根据自己的需求组合出各个年代所使用的的收集器。

一、新生代的垃圾收集器

1)Serial

Serial收集器是最基本、发展历史最悠久的收集器,在jdk1.3.1之前,Serial是新生代收集的唯一选择。顾名思义,这个收集器是一个单线程的收集器,这并不仅仅说明它只会使用一个CPU或一条线程去完成垃圾收集,更重要的是他在执行垃圾收集时,必须暂停其他所有的工作线程,直到收集结束(Stop The World)。

优点

  • (与其他单线程收集器相比)简单而高效
  • (限定单CPU环境下)没有线程交互的开销,可以获得最高的单线程收集效率

缺点

  • 单线程
  • 无法解决因回收造成的线程停顿

应用 :Client模式下的虚拟机

2)ParNew

ParNew收集器其实就是多线程的Serial收集器,ParNew收集器除了多线程之外并没有太多创新,但除了Serial之外却只有它能与CMS收集器配合

优点

  • 多线程
  • (ParNew默认开启的收集线程数与CPU数量相同)在CPU多于两个时有相当高的效率

缺点

  • CPU少的情况下线程交互开销较大

应用 :Server模式下的虚拟机

3)ParallelScavenge

ParallelScavenge收集器,也常被称为“吞吐量优先”收集器,同样作为多线程的新生代收集器,ParallerlScavenge收集器的关注点是尽可能的缩短垃圾收集时用户线程的停顿时间。

吞吐量:
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

ParallelScavenge提供手动控制吞吐量的功能,但是停顿时间的缩短是以牺牲新生代空间和吞吐量换来的。新生代的空间减少后,GC的运行时间肯定会缩短,但也会导致GC频率的提升,因此并非手动指定更小的新生代空间就可以达到更好的效果。

特点:提供了手动和自动控制吞吐量的功能,自适应调节策略可以动态调整相关参数,是一个不错的选择

二、老年代的垃圾收集器

1)SerialOld(MSC)

SerialOld是Serial收集器的老年代版本,它同样是一个单线程的收集器,使用“标记——整理”算法

应用:

  • jdk1.5之前与ParallerScavenge配合使用
  • CMS的后备方案,在“Concurrent Mode Failure”时使用
2)ParallelOld

ParallelOld是ParallelScavenge收集器的老年代版本,使用多线程和“标记——整理”算法

应用:

  • jdk1.6之后开始提供
  • 在注重吞吐量和CPU资源敏感的场合,可以优先考虑ParallelScavenge + ParallelOld的组合
3)CMS

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。从名字”Mark Sweep”可以看出,CMS收集器是基于“标记——清除”算法实现的。

CMS的收集过程:

  • 初始标记(CMS initial mark):仅仅是标记一下GC Roots能直接关联到的对象,速度很快
  • 并发标记(CMS concurrent mark):进行GC Roots Trancing
  • 重新标记(CMS remark):修正并发标记期间因用户程序继续运作而导致标记变动的对象的标记记录(比初始标记时间略长,但远比并发标记时间短)
  • 并发清除(CMS concurrent sweep)

其中初始标记重新标记两个步骤仍需”Stop The Word

由于整个过程中耗时最长的并发标记、并发清除过程都可以与用户线程一起工作,所以总体上说,CMS收集器的内存回收过程与用户线程是并发执行的。

优点:

  • 并发收集
  • 低停顿

缺点:

  • 对CPU资源非常敏感 : CMS默认启动的回收线程是(CPU数+3)/4,当CPU4个以上是,并发回收时垃圾收集线程不少于25%的CPU资源,并且随着CPU的增加而下降。CPU少于4个时,CMS对CPU的负载较大。为了解决这种问题而提出的“增量式并发收集器”(Incremental Concurrent Mark Sweep / i-CMS)目前已不再提倡使用。
  • 无法收集浮动垃圾(Floating Garbage ): 因为在CMS并发清除的过程中用户线程还在运行,这一部分的垃圾出现在标记过程之后,被称为“浮动垃圾”。CMS无法在当次收集中处理它们,只好留到下次GC再清理,为了保证用户线程的运行,CMS不能等到老年代几乎被填满才开始GC,必须预留出足够的空间给用户线程。如果在CMS运行期间预留的内存无法满足程序需求,就会出现“Concurrent Mode Failure”失败,而导致另一次FullGC产生。
  • “标记——清除”算法导致的大量内存空间碎片:大量空间碎片的产生可能会导致大对象分配时的内存不足,从而引发FullGC。CMS提供了两种开启内存碎片整理的功能。

三、G1收集器

G1(Garbage First)收集器是收集技术最前沿的收集器之一,在jdk1.7u4中,SUN公司才将它付诸商用。

特点:

  • 并行与并发:G1能充分利用CPU,可使用多个CPU或CPU核心缩短Stop The World停顿的时间,G1可以使用并发的方式使Java程序继续运行
  • 分代收集:虽然G1可以独立管理整个GC堆,但它能够采用不同的方式去处理不同代的对象
  • 空间整合:G1从整体来看是基于“标记——整理”算法来实现的,从局部(两个Region)来看是基于“复制”算法实现的,G1运作期间不会产生内存空间碎片。这种特性有利于程序长时间运行,分配大对象时,不会因为无法找到连续内存空间而提前引发下一次GC
  • 可预测的停顿:G1能够建立可预测的停顿时间模型。

G1将整个Java堆划分成多个大小相等的区域(Region),虽然还保留新生代和老年代的概念,但是两者不再是物理隔离的了,它们都是一部分Region(不需连续)的集合。

G1通过跟踪各个Region里垃圾堆积的价值大小,在后台维护一个优先列表( 建立可预测的停顿时间模型 ),从而有计划的避免整个堆上的垃圾收集,优先回收价值最大的Region,尽可能的提升效率。

G1收集器运作的步骤:

  • 初始标记(Initial Marking):仅仅只标记一下GC Roots能直接关联的对象,并修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象。需要停顿线程,但耗时很短。
  • 并发标记(Concurrent Marking):从GC Roots中开始对堆中的对象进行可达性分析耗时较长,但可与用户程勋并发执行
  • 最终标记(Final Marking):修正并发标记阶段因为用户程序继续运行而导致标记改变的对象的标记记录。需要线程停顿,但可与用户程序并发。
  • 筛选回收(Live Data Counting and Evacuation):对各个Region的回收价值和回收成本排序,根据用户期望制定回收计划

应用:追求低停顿的场合

发表评论

邮箱地址不会被公开。 必填项已用*标注