【JVM】3.2、垃圾收集器(二)

  • Serial 收集器
    • 特性
    • 应用场景
    • 优势
    • 运作过程
  • ParNew收集器
    • 特性
    • 应用场景
    • 优势
    • 运作过程
  • Parallel Scavenge 收集器
    • 特性
    • 对比分析
      • Parallel Scavenge收集器 VS CMS等收集器
      • Parallel Scavenge收集器 VS ParNew收集器
    • 应用场景
    • 运作过程
  • Serial Old 收集器
    • 特性
  • Parallel Old收集器
    • 特性
  • CMS收集器
    • 特性
    • 应用场景
    • 运作过程
    • 缺点
    • 了解
  • G1 收集器
    • 特性
    • 应用场景
      • 是否一定采用G1呢?也未必!
    • 执行过程
  • 总结

Serial 收集器

特性

最基本、发展历史最久的收集器,采用复制算法的单线程收集器,单线程一方面意味着它只会使用一个CPU或一条线程去完成垃圾收集工作,另一方面也意味着在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束为止,这个过程也称为 Stop The world。后者意味着,在用户不可见的情况下要把用户正常工作的线程全部停掉,这显然对很多应用是难以接受的。

应用场景

Serial收集器依然是虚拟机运行在Client模式下的默认新生代收集器。 在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的

优势

简单而高效(与其他收集器的单线程相比),对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。比如在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的。

运作过程

Serial 收集器 和 Serial Old 收集器

ParNew收集器

特性

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集外,其余行为和Serial收集器完全一样,包括Serial收集器可用的所有控制参数、收集算法、Stop The world、对象分配规则、回收策略等都一样。在实现上也共用了相当多的代码。

应用场景

ParNew收集器是许多运行在Server模式下的虚拟机中首选的新生代收集器。很重要的原因是:除了Serial收集器之外,目前只有它能与CMS收集器配合工作(看图)。在JDK1.5时期,HotSpot推出了一款几乎可以认为具有划时代意义的垃圾收集器-----CMS收集器,这款收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程同时工作。

优势

在单CPU中的环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销,甚至由于线程交互的开销,该收集器在两个CPU的环境中都不能百分百保证可以超越Serial收集器。当然,随着可用CPU数量的增加,它对于GC时系统资源的有效利用还是很有好处的,它默认开启的收集线程数与CPU数量相同。

运作过程

ParNew 收集器 和 Serial Old 收集器

Parallel Scavenge 收集器

特性

Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,也是并行的多线程收集器。

对比分析

Parallel Scavenge收集器 VS CMS等收集器

Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。由于与吞吐量关系密切,Parallel Scavenge收集器也经常称为“吞吐量优先”收集器。

Parallel Scavenge收集器 VS ParNew收集器

Parallel Scavenge收集器与ParNew收集器的一个重要区别是它具有自适应调节策略。

应用场景

Parallel Scavenge收集器是虚拟机运行在Server模式下的默认垃圾收集器。
停顿时间短适合需要与用户交互的程序,良好的响应速度能提升用户体验;高吞吐量则可以高效率利用CPU时间,尽快完成运算任务,主要适合在后台运算而不需要太多交互的任务。
该收集器以高吞吐量为目标,就是减少垃圾收集时间,从而让用户代码获得更长的运行时间。所以适合那些运行在多个CPU上,并且专注于后台计算的应用程序,例如:执行批量处理任务、订单处理,工资支付,科学计算等。

运作过程

Parallel Scavenge 收集器 和 Parallel Old 收集器

Serial Old 收集器

特性

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


Parallel Old收集器

特性

Parallel 收集器的老年代版本,使用多线程和”标记-整理“算法。


CMS收集器

特性

CMS(Concurrent Mark Sweep)收集器:基于”标记-清除“算法实现的(不进行压缩,会产生内存碎片),特点是:并发收集,低停顿。
是HotSpot在JDK1.5推出的第一款真正意义上的并发(Concurrent)收集器;第一次实现了让垃圾收集线程与用户线程(基本上)同时工作;

应用场景

与用户交互较多的场景。CMS 收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网或者B/S系统的服务端上,这类应用尤其注重服务的响应速度,希望系统停顿时间最短,以给用户带来极好的体验。CMS收集器就非常符合这类应用的需求。

运作过程

对于前面几种收集器来说更复杂一些,整个过程分为4个步骤:

  1. 初始标记(CMS initial mark),初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,但需要“Stop The World”。
  2. 并发标记(CMS concurrent mark),并发标记阶段就是进行GC Roots Tracing的过程,刚才产生的集合中标记出存活对象;应用程序也在运行;并不能保证可以标记出所有的存活对象;
  3. 重新标记(CMS remark),重新标记阶段是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录;仍然需要需要”Stop The World“,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
  4. 并发清除(CMS concurrent sweep),并发清除阶段会清除对象,回收所有的垃圾对象。

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

CMS 收集器

缺点

CMS收集器对CPU资源非常敏感,其实,面向并发设计的程序都对CPU资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量会降低。CMS默认启动的回收线程数=(CPU数量+3)/ 4,也就是当CPU在4个以上时,并发回收时垃圾收集线程不少于25%的CPU资源,并且随着CPU数量的增加而下降。但是当CPU不足4个(譬如2个)时,CMS对用户程序的影响就可能变得更大,可能会无法接受。

了解

增量式并发收集器:针对上述这种情况,曾出现了”增量式并发收集器“,类似使用抢占式来模拟多任务机制的思想,让收集线程和用户线程交替运行,减少收集线程运行时间;但效果并不理想,JDK1.6后官方就不再提倡用户使用。CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。

G1 收集器

特性

  1. 并行与并发,G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。
  2. 分代收集(收集范围包括新生代和老年代),与其他收集器一样,分代概念在G1中依然得以保留。G1可以不需要其他收集器配合就能独立管理整个GC堆,它能够采用不同的方式去处理不同时期的对象。使用G1收集器时,Java堆的内存布局有了很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。
  3. 空间整合(结合多种垃圾收集算法,不产生碎片),与CMS的“标记—清理”算法不同,G1从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
  4. 可预测的停顿(低停顿的同时实现高吞吐量),这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。

应用场景

  1. 面向服务端应用,针对具有大内存、多处理器的机器;最主要的应用是为需要低GC延迟,并具有大堆的应用程序提供解决方案;如:在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒;
  2. 用来替换掉JDK1.5的CMS收集器;(1)、超过50%的Java堆被活动数据占用;(2)、对象分配频率或年代提升频率变化很大;(3)、GC停顿时间过长(长与0.5至1秒)。
是否一定采用G1呢?也未必!

如果现在采用的收集器没有出现问题,不用着急去选择G1;如果应用程序追求低停顿,可以尝试选择G1;是否替代CMS需要实际场景测试才知道。

执行过程

  1. 初始标记(Initial Marking),初始标记阶段仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时很短。
  2. 并发标记(Concurrent Marking),并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行。
  3. 最终标记(Final Marking),最终标记阶段是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行。
  4. 筛选回收(Live Data Counting and Evacuation),筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分价值高的Region区的垃圾对象,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。回收时,采用“复制”算法,从一个或多个Region复制存活对象到堆上的另一个空的Region,并且在此过程中压缩和释放内存。

总结

收集器 串行、并行or并发 新生代/老年代 算法 目标 适用场景
Serial 串行 新生代 复制算法 响应速度优先 单CPU环境下的Client模式
Serial Old 串行 老年代 标记-整理 响应速度优先 单CPU环境下的Client模式、CMS的后备预案
ParNew 并行 新生代 复制算法 响应速度优先 多CPU环境时在Server模式下与CMS配合
Parallel Scavenge 并行 新生代 复制算法 吞吐量优先 在后台运算而不需要太多交互的任务
Parallel Old 并行 老年代 标记-整理 吞吐量优先 在后台运算而不需要太多交互的任务
CMS 并发 老年代 标记-清除 响应速度优先 集中在互联网站或B/S系统服务端上的Java应用
G1 并发 both 标记-整理+复制算法 响应速度优先 面向服务端应用,将来替换CMS

你可能感兴趣的:(【JVM】3.2、垃圾收集器(二))