垃圾收集器 2020面试必看

HotSpot虚拟机中的垃圾收集器

上面只是介绍了垃圾收集算法的原理,而由于HotSpot虚拟机的垃圾收集是按照分代完成的,所以虚拟机中实现了多个垃圾收集器。这里依据的是JDK 1.7之后的实现,垃圾收集器如下图所示:

 

这张图体现了HotSpot虚拟机中各个垃圾收集器的关系,其中上面的三个垃圾收集器工作在新生代,下面的三个收集器工作在老年代,而G1收集器在两个部分都可以工作。收集器之间的连线表明两个收集器可以协同工作。下面来分别介绍一下各个垃圾收集器的原理、特性和使用场景。

(1)Serial收集器

Serial收集器是最基本的、历史最悠久的收集器,曾经是JDK 1.3.1之前虚拟机的新生代收集的唯一选择。Serial这个名字揭示了这是一个单线程的垃圾收集器,特点如下:

· 仅仅使用一个线程完成垃圾收集工作;

· 在垃圾收集时必须暂停其他所有的工作线程,知道垃圾收集结束;

· Stop the World是在用户不可见的情况下执行的,会造成某些应用响应变慢;

· 使用复制算法;

Serial收集器的工作流程如下图:

 

 

 

 

虽然如此,Serial收集器依然是虚拟机运行在Client模式下的默认新生代收集器。它的优点同样明显:简单而高效(单个线程相比),并且由于没有线程交互的开销,专心做垃圾收集自然课获得最高的单线程效率。在一般情况下,垃圾收集造成的停顿时间可以控制在几十毫秒甚至一百多毫秒以内,还是可以接受的。

(2)ParNew收集器

ParNew收集器其实是Serial收集器的多线程版本,与Serial不同的地方就是在垃圾收集过程中使用多个线程,剩下的所有行为包括控制参数、收集算法、Stop the World、对象分配规则和回收策略等都一样。ParNew收集器也使用复制算法。ParNew收集器的工作流程如下图:

 

ParNew收集器看似没有多大的创新之处,但却是许多运行在Server模式下的虚拟机中首选的新生代收集器,因为,除了Serial收集器外,目前只有ParNew收集器能够与CMS收集器配合工作,而CMS收集器是HotSpot在JDK 1.5时期推出的具有划时代意义的垃圾收集器(后面会介绍到)。

ParNew收集器在单个线程的情况下由于线程交互的开销没有Serial收集器的效果好。不过,随着CPU个数的增加,它对于GC时系统资源的有效利用还是很有好处的。它默认开启的收集线程数与CPU的数量相同。可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。

(3)Parallel Scavenge收集器

Parallel Scavenge收集器和ParNew类似,是一个新生代收集器,使用复制算法,又是并行的多项成收集器。不过和ParNew不同的是,Parallel Scavenge收集器的关注点不同。

CMS等收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目的则是达到一个可控制的吞吐量。吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+运行垃圾收集时间)。如果虚拟机一共运行100分钟,垃圾收集运行了1分钟,那么吞吐量就是99%。

停顿时间越短就越适合与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效的利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

Parallel Scavenge收集器提供了两个参数来精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。

MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器将尽可能在给定时间内完成垃圾收集。不过垃圾收集时间的缩短是以牺牲吞吐量和新生代空间为代价的,短的垃圾收集时间会导致更加频繁的垃圾收集行为,从而导致吞吐量的降低。

GCTimeRatio参数的值是一个大于0且小于100的整数,也就是垃圾收集时间占总时间的比率,相当于吞吐量的倒数。如果设置为19,那允许的最大GC时间就是总时间的5%(1/(1+19))。默认是99,也就是允许最大1%的垃圾收集时间。

Parallel Scavenge收集器也叫吞吐量优先收集器,它还有一个参数-XX:UseAdaptiveSizePolicy,这是一个开关参数,当这个参数打开后,就不需要手工指定新生代的大小(-Xmn)、Eden和Survivor的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最适合的停顿时间或最大的吞吐量,这叫GC自适应的调节策略。这也是Parallel Scavenge收集器和ParNew收集器的一个重要区别。

(4)Serial Old收集器

Serial Old是Serial的老年版本,在Serial的工作流程图中可以看到,Serial Old收集器也是一个单线程收集器,使用“标记-整理”算法。这个收集器主要给Client模式下的虚拟机使用。如果在Serve模式下,它有两个用途:一个是在JDK 1.5之前的版本中与Parallel Scavenge收集器搭配使用;另一个就是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。这个收集器的工作流程在Serial的后半部分有所体现。

(5)Parallel Old收集器

Parallel Old收集器是Parallel Scavenge收集器的老年版本,它也使用多线程和“标记-整理”算法。这个收集器是在JDK 1.6开始提供。

在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器的组合。Parallel Old收集器的工作流程如下:

 

(6)CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。在重视响应速度和用户体验的应用中,CMS应用很多。

CMS收集器使用“标记-清除”算法,运作过程比较复杂,分为4个步骤:

· 初始标记(CMS initial mark)

· 并发标记(CMS Concurrent mark)

· 重新标记(CMS remark)

· 并发清除(CMS Concurrent Sweep)

其中,初始标记和并发标记仍然需要Stop the World、初始标记仅仅标记一下GC Roots能直接关联到的对象,速度很快,并发标记就是进行GC RootsTracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段长,但远比并发标记的时间短。

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

CMS的优点就是并发收集、低停顿,是一款优秀的收集器。不过,CMS也有缺点,如下:

· CMS收集器对CPU资源非常敏感。CMS默认启动的回收线程数是(CPU数量+3)/4,当CPU个数大于4时,垃圾收集线程使用不少于25%的CPU资源,当CPU个数不足时,CMS对用户程序的影响很大;

· CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC;

· CMS使用标记-清除算法,会产生内存碎片;

 

虚拟机提供了-XX:+UseCMSCompactAtFullCollection参数来进行碎片的合并整理过程,这样会使得停顿时间变长,虚拟机还提供了一个参数配置,-XX:+CMSFullGCsBeforeCompaction,用于设置执行多少次不压缩的Full GC后,接着来一次带压缩的GC。

 

(7)G1收集器

G1(Garbage first)收集器是最先进的收集器之一,是面向服务端的垃圾收集器。与其他收集器相比,G1收集器有如下优点:

· 并行与并发:有些收集器需要停顿的过程G1仍然可以通过并发的方式让用户程序继续执行;

· 分代收集:可以不使用其他收集器配合管理整个Java堆;

· 空间整合:使用标记-整理算法,不产生内存碎片;

· 可预测的停顿:G1除了降低停顿外,还能建立可预测的停顿时间模型;

G1中也有分代的概念,不过使用G1收集器时,Java堆的内存布局与其他收集器有很大的差别,它将整个Java堆划分为多个大小相等的独立区域(Region),G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划的避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里垃圾堆积的价值大小(回收所获得的空间大小以及回收所需要的时间的经验值),在后台维护一个优先列表,每次优先收集价值最大的那个Region。这样就保证了在有限的时间内尽可能提高效率。

G1收集器的大致步骤如下:

· 初始标记(Initial mark)

· 并发标记(Concurrent mark)

· 最终标记(Final mark)

· 筛选回收(Live Data Counting and Evacuation)

收集器的流程如下图:

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值