垃圾收集器的选择根据具体的应用,不存在万能的收集器。
1、Serial收集器
收集新生代的垃圾
该收集器是一个单线程工作的收集器。它只会使用一个处理器或一条收集线程去完成垃圾收集工作,更重要的是它在垃圾收集时,必须暂停其他所有工作线程,直到它收集结束。
它依然是HotSpot虚拟机运行在客户端模式下的默认新生代收集器,它相对于其他垃圾收集器来说简单而高效,对于内存资源受限的环境,它是所有收集器里额外内存消耗最小的。
2、ParNew收集器
该收集器是Serial收集器的多线程版本,用于收集新生代的垃圾。
它的控制参数、收集算法、Stop The World、对象分配规则、回收策略都与Serial收集器完全一致。
使用CMS收集器收集老年代的时候新生代只能选择ParNew或Serial收集器中的一个
JDK9之前,ParNew加CMS收集器的组合是官方推荐的服务端模式下的收集器解决方案。
( 官方取消了ParNew加Serial Old以及Serial加CMS组合的支持)
可以理解为从此以后ParNew合并入CMS,成为它专门处理新生代的组成部分。
3、Parallel Scavenge收集器
收集新生代的垃圾,它基于标记-复制算法实现的收集器,也是能够并行收集的多线程收集器。
它的目标则是达到一个可控制的吞吐量,运行用户代码的时间与处理器总消耗时间的比值。
适合在后台运算而不需要太多交互的分析任务。
它提供了两个参数来控制吞吐量:
-XX:MaxGGPauseMillis:控制最大垃圾收集停顿时间
-XX:GCTimeRatio:直接设置吞吐量大小
还有一个参数-XX:+UseAdaptiveSizePolicy,这是一个开关参数,当这个参数被激活之后,就不需要人工指定新生代的大小、Eden和Survivor区的比例、晋升老年代对象大小等细节参数,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。
4、Serial Old收集器
收集老年代的垃圾,是一个单线程收集器,使用标记-整理算法。该收集器的主要意义是供给客户端模式下的HotSpot虚拟机使用。
服务端模式下的两种用途:
JDK5以及之前和Parallel Scavenge收集器搭配使用
作为CMS收集器发生失败时的后备预案。
5、Parallel Old收集器
是Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。
JDK6才开始提供,在此之前新生代使用Parallel Scavenge,老年代只能使用Serial Old收集器,因为单线程的老年代收集器无法充分利用服务器多处理器的并行处理能力,所以这种组合不是很优秀。
在注重吞吐量或者处理器资源较为稀缺的场合,可以优先考虑Parallel Scavenge加Parallel
Old收集器这对组合。
6、CMS收集器
是一种以获取最短回收停顿时间为目标的收集器,是基于标记-清除算法实现的,负责收集老年代的垃圾。
它的收集过程分为四个步骤
1)初始标记
标记一些GC Roots能直接关联到的对象,速度很快
2)并发标记
从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程可以与垃圾收集线程一起并发运行
3)重新标记
修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录
4)并发清除
清理删除掉标记阶段判断的已经死亡的对象,该阶段可以与用户线程同时并发运行。
1、3阶段仍然需要Stop The World
缺点:
对处理器资源非常敏感(在并发阶段会占用一部分线程而导致应用程序变慢,降低总吞吐量)
无法处理浮动垃圾而导致失败进而导致另一次的Full GC的产生
因为基于标记-清除算法而导致产生大量的内存碎片
7、G1收集器
是主要面向服务端应用的垃圾收集器
JDK9之后,G1宣告取代Parallel Scavenge加Parallel Old组合,成为服务端模式下的默认垃圾收集器。它可以面向堆内存任何部分来组成回收集进行回收。
具体内容请参考《深入理解Java虚拟机》
各种垃圾收集器之间的关系,两个垃圾收集器之间存在连线就说明两者可以搭配使用
欢迎关注我的微信公众号,分享leetcode解题心得和Java后端的相关知识