jvm(五):垃圾收集器的种类

上文对垃圾收集的算法做了一个简单的梳理,但那些只是理论算法,并不是jvm中实际的收集器。本节将对这种不同的垃圾收集器做一个简单的阐述。
总的来说,jvm将内存空间(堆)分为老年代和新生代,然后垃圾收器是针对不同年代作用的。
这里写图片描述
上图显示了jvm中目前(1.7)采用的垃圾收集器,除了G1收集器外,其他收集器都是只服务于新生代和老年代中的一个。
连线表示新生代的垃圾收集器和老年代的垃圾收集器可以协同工作。

Serial

对应上图中新生代最左边的收集器,作为新生代的第一个出现的收集器,serial收集器是单线程的。

Serial收集器采用“复制”算法

该收集器的特点即是:
- 单线程,即只会使用一个CPU或一条收集线程去完成垃圾收集的工作
- 在垃圾回收时,必须暂停其他所有线程的工作线程,即所谓的“Stop The World”

当前,jvm在Client模式下,默认的新生代收集器仍然是Serial收集器,虽然它有着上述两个重大的缺点,但也有这简单高效的优点。
其运行示意图如下:
这里写图片描述

Serial Old

是一款老年代收集器,从图中就可以看出,Serial Old和Serial可以协同工作,实际上Serial Old收集器是Serial的老年代版本,但采用的算法却不同。

Serial Old收集器采用“标记-整理”算法

可以看出Serial Old可以与其他三个新生代的垃圾回收器协同作用,故当老年代使用CMS收集器出现故障时(Concurrent Mode Failure),可以作为CMS的后备选择。
Serial和Serial Old的协同工作模式如下
这里写图片描述

ParNew

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾回收之外,其他甚至包括控制参数(-XX:SurvivorRatio)都与Serial一样,即也需要停止所有用户线程,采用复制算法等。
查看上图的协作关系可以发现,除了Serial,只有ParNew能与CMS协同作用,因此在jvm的Server模式下,ParNew是老年代的首先垃圾收集器。
因此在多CPU模式下,ParNew搭配CMS将是很好的选择。
这里写图片描述

Parallel Scavenge

最后一个新生代垃圾收集器,同样是并行的复制算法收集器,那么和ParNew的区别是什么呢?
Parallel Scavenge的特点在于达到一个可控制的吞吐量(Throughput),所谓吞吐量就是CPU用于运行代码的时间和CPU总消耗时间的比值,即吞吐量=运行用户代码的时间/(运行用户代码时间+垃圾收集时间)
高吞吐量可以有效的利用CPU,尽可能完成程序的任务,也就是越适合在后台运算而不需要太多交互任务。
另外,Parallel Scavenge提供了两个参数用于精确控制吞吐量——-XX:MaxGCPauseMillis控制最大垃圾收集停顿时间,-XX:GCTimeRatio直接设置吞吐量。
主要注意的是,XX:MaxGCPauseMillis设置的越小,吞吐量则必然越小。
Parallel Scavenge还有个参数是GC自适应的调节策略,这个参数可以使得用户不用调节其他参数,其他参数将自动有jvm去动态设置。

Parallel Old

Parallel Scavenge的老年代版本收集器,只能和Parallel Scavenge配合使用,使用“标记-整理”算法。
该收集器就是针对Parallel Scavenge的,因为Parallel Scavenge除了Parallel Old外,就只能和Serial Old配合使用(不能和CMS配合使用),这导致Parallel Scavenge和Serial Old的组合并不能达到Parallel Scavenge的初衷——吐吞量最大化。
为了达到“吞吐量优先”,优势就有了Parallel Old收集器,这个组合常用于注重吞吐量以及CPU资源敏感的场合。
这里写图片描述

CMS

Concurrent Mark Sweep,从名字就可以看出是并发的垃圾收集器,且采用标记-清除算法。
CMS的垃圾清理分为四个阶段

  • 初始标记(CMS initial mark)
    这一阶段仍然需要Stop The World,该阶段的任务仅仅是标记一下GC Roots能直接关联到的对象。
    我们知道GC Roots是使用OopMap来获取的,这说明这一阶段(初始标记)的速度是很快的。

  • 并发标记(CMS concurrent mark)
    这一阶段是GC Roots后的延伸,即找出GC Roots能关联到的对象,即GC Roots Tracing的过程。
    该阶段是和用户线程并发执行的

  • 重新标记(CMS remark)
    由于上一阶段并发标记是并发的,这意味着在进行GC Roots Tracing时,用户进行仍会改变已标记的对象的状态。故该阶段重新标记也是Stop The World,是为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分,该阶段的时间比初始标记略长,但比并发标记时间短。

  • 并发清除(CMS concurrent sweep)
    和用户程序一起运行。清除上述标记的垃圾。

CMS的四个阶段中耗时最长的并发标记和并发清除是和用户线程一起执行的,而耗时较短的初始标记和重新标记则耗时较短。
这里写图片描述
但CMS仍有如下缺点:

  • 对CPU资源非常敏感
    并发并不是万无一失的,因为这将导致垃圾收集线程和用户线程竞争资源。当CPU数量少时,尤为如此。
    于是这就有一个两难的问题了,我们希望垃圾收集线程和用户线程并发, 但问题是并发意味着抢占资源,当CPU数量少时,垃圾收集线程将和用户线程抢占CPU,这给了我们启发,当CPU数较高时,才建议使用CMS.

  • 无法有效处理浮动垃圾
    由于并发标记和并发清除阶段仍有用户线程,因此会导致不断有垃圾产生,这部分垃圾无法在当次阶段被清理,这部分垃圾就被称为“浮动垃圾”,另一方面,由于在清理的同时伴随着用户线程,因此堆上还需要预留空间给用户线程使用。
    这导致CMS运行期间,可能预留的空间无法满足程序的需要,此时就会出现“Concurrent Mode Failure”,此时CMS垃圾收集器失效,将会启用Serial Old。

  • 垃圾碎片
    一开始就说过,CMS是“标记-清除”的,因此产生空间碎片。
    太多的空间碎片会导致内存分布太散,无法容纳大对象,当无法容纳大对象时,就会触发一次Full GC,会在Full GC发生前启用一次内存整理合并。

G1

Garbage-First,从上图的协作关系可以看出,G1既可以作用于新生代又可以作用于老年代,那么具体是如何实现的呢?

对于G1来说,java堆被划分为多个大小相等的独立区域(Region),并跟踪每个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收时所需要的经验值),在后台维护一个优先列表,并根据允许的收集时间,优先回收价值最大的Region。

虽然如此,但G1的实现却有许多值得注意的细节,比如:Region中的对象并非只被该Region所引用
这导致,每次对每个Region的对象做可达性分析时,还需要扫描其他的Region。但其实G1不是这么做的,不仅是G1,其他收集器也采用这样的做法:jvm使用Remember Set来记录Region里的对象。
G1的垃圾回收也可划分为以下几步:

  • 初始标记(Initial Marking)
    和CMS的第一阶段一样,仅仅是标记GC Roots能直接关联到的对象,并修改TAMS(Next Top at Mark Start)的值,让下一阶段的用户在并发执行时,可以正确的创建对象(这也说明Region内是采用标记-整理算法)。同样是需要Stop The World
  • 并发标记(Concurrent Marking)
    同CMS的并发标记,耗时较长,但可以与用户线程并发执行。
  • 最终标记(Final Marking)
    同样是为了修正在并发标记期间引起的变动。不同的是,jvm将对象变化记录在线程Remembered Set Logs里面,该阶段需要把Remembered Set Logs的数据合并到Remembered Set中,该阶段是需要Stop The World的,但垃圾回收线程却可以并行执行。
  • 筛选回收(Live Data Counting and Evacuation)
    对各个Region的回收价值和成本进行排序,根据用户所希望的GC停顿时间来执行回收计划。
    这里写图片描述
    上述讲完G1的执行过程,下面简单介绍下G1的特点:

  • 并行与并发
    G1在并发标记阶段,用户线程和垃圾回收线程并发执行,最终标记和筛选回收阶段是垃圾回收线程并行执行,

  • 分代收集
  • 空间整合
    与CMS的“标记-清理”不同,G1从整体来看是基于“标记-整理”的,从局部(两个Region之间)来看是基于“复制”算法的,无论如何G1都不会产生垃圾碎片。
  • 可预测的停顿
    能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值