1.概述

Java应用启动的时候,除了配置Xms以及Xmx参数(Xmx:InitialHeapSize, Xms:MaxHeapSize),还需要选择合适的垃圾收集器。
截止Jdk1.8,共提供了7款垃圾收集器,每一款垃圾收集器都具有不同的特点。我们所需要做的就是,根据Java应用的特点已经部署环境,确定不同垃圾收集器的组合。这几款垃圾收集器之间联系如下图所示:

由上图可知,Serial,ParNew,Parallel Scavenge主要负责Young generation区域的垃圾回收,CMS,Serial Odl, Parallel Old主要负责Tenured generation区域的垃圾回收,G1在Young generation以及Tenured generation区域均可以使用(详细原因在下文会进行阐述)。

2.垃圾收集器概述

jdk提供了多重垃圾收集器,下文会提供主流的垃圾收集器搭配组合,各种组合按照特点分为以下三类:

  • 串行收集器:Serial + Serial Old;
  • 并行收集器: Parallel Scavenge + Parallel Old,专注于应用吞吐量;
  • 并发收集器:CMS,G1,专注于响应时间。

2.1 Serial收集器

Serial收集器(Serial + Serial Old)的主要特点是单线程回收资源。当需要执行垃圾回收时,程序会暂停一切工作(又称为Stop The World,STW),使用复制算法完成垃圾清理工作。

优点:

  • 简单高效,是Client模式下默认的垃圾收集器;
  • 对于资源受限的环境,比如单核(例如Docker中设置单核),单线程效率较高;
  • 内存小于一两百兆的桌面程序中,交互有限,则有限的STW是可以接受的。

缺点:

  • 垃圾回收速度较慢且回收能力有限,频繁的STW会导致较差的使用体验。

ParNew收集器是Serial收集器的多线程版本,除了使用多线程进行垃圾收集工作,其他的控制参数,收集算法,对象分配规则等均与Serial收集器一致。
ParNew收集器在单核/双核环境下,效率未必有Serial收集器工作效率高(多线程切换开销等因素限制),当然随着核数的增加,其性能也会得到较大的提升。

2.2 Parallel收集器

Parallel收集器(Parallel Scavenge + Parallel Old)相比于Serial收集器的主要特点是,其是通过多线程完成垃圾的清理工作。其中Parallel Scavenge使用复制算法完成垃圾收集(Parallel Old使用标记整理算法),如果从这一点看其与ParNew相似,但实际上两者的出发点存在区别,区别如下所示:

  • ParNew出发点在于加速资源回收的速度,以减少应用的STW时间;
  • Parallel Scavenge出发点在于资源回收的吞吐量(吞吐量:用户线程时间/(用户线程时间 + GC线程时间)).

高吞吐量适合于交互较少的后台应用程序(诸如科学计算应用),能够更加充分的压榨CPU。开发者可以根据应用的实际情况,通过调整以下两个参数追求最优性能:

  • 最大停顿时间:垃圾收集器在执行垃圾回收时终端应用执行的最大时间间隔,-XX:MaxGCPauseMills;
  • 吞吐量:执行垃圾收集的时间与执行应用的时间占比,-XX:GCTimeRatio=,垃圾收集时间占比:1/(1+N)。

2.3 CMS收集器

CMS(Concurrent Mark Sweep)收集器是jdk 1.5推出的第一款真正意义上的并发收集器(针对老年代),实现了让垃圾收集器与用户线程(近似)同时工作,其具有以下特点:

  • 基于"标记-清除"算法;
  • 以获取最短回收停顿时间为目标;
  • 并发收集,停顿时间短。

CMS的垃圾收集过程比较复杂,主要步骤如下所示:

(1) CMS Initial Mark:初始标记Root(会STW,单线程执行,不过因为仅仅把GC Roots的直接可达对象标记一下,所以速度较快);

(2) CMS Concurrent Mark:并发标记;

(3) CMS Concurrent Preclean: 并发预清理;

(4) CMS Remark: 并发标记(会STW,此步骤是因为在并发标记的过程中可能会产生新的垃圾,需要重新标记新产生的垃圾);

(5) CMS Concurrent Sweep: 并发清除;

(6) CMS Concurrent Reset: 并发重置。

以上步骤中,最为耗费时间的并发标记与并发清除阶段,不需要应用程序暂停执行,所以垃圾回收的停顿时间较短。

缺点:

  • 对CPU资源敏感:并发收集虽然不会暂停应用程序,但是会占用CPU资源从而降低应用程序的执行效率(CMS默认收集线程数量=(CPU数量 + 3) / 4);
  • 产生浮动垃圾:在并发清除时,用户线程会产生新的垃圾,称之为浮动垃圾(并发清除时需要预留内存空间,不能像其他收集器在老年代几乎填满之后再进行收集工作)。
  • 产生空间碎片:使用"标记-清除"算法,会产生大量不连续的内存碎片,从而导致在分配大内存对象时,无法找到足够的连续内存,从而需要提前触发一次Full GC操作。

针对以上缺点,可以从如下参数进行改进:

  • -XX:ConcGCThreads:并发的GC线程数,从而降低CPU敏感度;
  • -XX:CMSInitiatingOccupancyFraction:合理设置CMS的预留内存空间;
  • -XX:+UseCMSCompactAtFullGCCollection: FullGC之后执行压缩操作,消减内存碎片;
  • -XX:CMSFullGCBeforeCompaction: 执行多次FullGC之后执行压缩操作,消减内存碎片。

2.4 G1收集器

需要注意的是G1垃圾收集器在新生代以及老年代都能进行工作,这是因为相比于前面所介绍的垃圾收集器,它具有不同的堆内存结构。以前的垃圾收集器分代是划分为新生代、老牛代、持久带等

G1将内存划分为多个大小相同的Region(1-32M,上限2048个),每个Region均拥有自己的分代属性,这些分代不需要连续。通过划分Region,G1可以根据计算老年代对象的效益率,优先回收具有最高效益率的对象(分代的内存不连续,GC搜索垃圾时需要全盘扫描找出对象引用情况,G1通过在每个Region中维护一个Remembered Set记录对象引用情况解决此问题)。具体如下图所示:

G1提供了两种GC模式,Young GC以及Mixed GC,两种GC都会STW。

2.4.1 Young GC

选定所有年轻代里的Region。通过控制年轻代的region个数,即年轻代内存大小,来控制young GC的时间开销。

2.4.2 Mixed GC

选定所有年轻代里的Region,外加根据global concurrent marking统计得出收集收益高的若干老年代Region,在用户指定的开销目标范围内尽可能选择收益高的老年代Region。

Mixed GC不是Full GC,它只能回收部分老年代的Region,如果mixed GC实在无法跟上程序分配内存的速度,导致老年代填满无法继续进行Mixed GC,就会使用serial old GC(full GC)来收集整个GC heap(此时效率就会很低下)。所以我们可以知道,G1是不提供Full GC的。

在执行Mixed GC之前需要进行并发标记过程(Global Concurrent Marking),具体步骤如下图所示:

  • Initial marking phase: 标记GCRoots(会STW);
  • Root region scanning phase: 标记存活Region;
  • Concurrent marking phase:标记存活的对象;
  • Remark phase:重新标记(会STW);
  • Cleanup phase: 回收内存。

需要注意,Mixed GC并不是一次性执行完,其会分为多个步骤执行(具体可见下一篇关于GC日志的文章)。在每次执行时,G1会计算每个Region中垃圾占内存分段比例,如果超过了-XX:G1MixedGCLiveThresholdPercent,则进行回收操作。此外,G1中可以设置堆内存中有多少空间允许浪费,即-XX:G1HeapWastePercent,在并发标记结束后,可以知道有多少空间要被回收,在每次Young GC和发生Mixed GC之前,会检查垃圾占比是否到达了此阈值,只有到达了,才会发生Mixed GC。

PS:
资料收集过程中,感谢以下作者文章的参考:
https://bdqfork.cn/articles/33
https://juejin.im/post/5bade237e51d450ea401fd71

如果您觉得我的文章对您有帮助,请关注我的微信公众号,谢谢!

Java垃圾收集器——Serial,Parallel,CMS,G1收集器概述的更多相关文章

  1. Serial,Parallel,CMS,G1四大GC收集器特点小结

    1.Serial收集器一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有的工作线程直到它收集结束.特点:CPU利用率最高,停顿时间即用户等待时间比较长.适用场景:小型应用通过JVM参数-XX:+ ...

  2. Java垃圾收集器——Parallel、G1收集器日志分析及性能调优示范

    开发过程中,经常需要对GC的垃圾收集器参数不断的进行动态调整,从而更充分的压榨机器性能,提升应用效率.本文将从常见的Parallel/G1垃圾收集器的GC日志着手,分析GC日志的具体含义,以及示范如何 ...

  3. 转Serial,Parallel,CMS,G1四大GC收集器特点小结

    转 https://blog.csdn.net/u013812939/article/details/48782343 1.Serial收集器 一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有 ...

  4. 深入理解JVM 垃圾收集器(下)G1收集器

    1.回顾CMS 1.1堆内存结构 1.2新生代GC 1.3老年代GC 2.G1收集器 2.1G1实现概览及使用场景 G1的推荐使用场景 2.2GC 2.2.1新生代GC 2.2.2老年代GC 老年代G ...

  5. JAVA G1收集器 第11节

    JAVA G1收集器 第11节 上两章我们讲了新生代和年老代的收集器,那么这一章的话我们就要讲一个收集范围涵盖整个堆的收集器——G1收集器. 先讲讲G1收集器的特点,他也是个多线程的收集器,能够充分利 ...

  6. JVM(11)之 G1收集器

    开发十年,就只剩下这套架构体系了! >>>   在前两篇博文中讲解了新生代和年老代的收集器,在本篇博文中介绍一个收集范围涵盖整个堆的收集器--G1收集器.  先讲讲G1收集器的特点, ...

  7. CMS垃圾收集器与G1收集器

    1.CMS收集器 CMS收集器是一种以获取最短回收停顿时间为目标的收集器.基于“标记-清除”算法实现,它的运作过程如下: 1)初始标记 2)并发标记 3)重新标记 4)并发清除 初始标记.从新标记这两 ...

  8. 垃圾收集器之:G1收集器

    G1垃圾收集器是一种工作在堆内不同分区上的并发收集器.分区既可以归属于老年代,也可以归属新生代,同一个代的分区不需要保持连续.为老年代设计分区的初衷是我们发现并发后台线程在回收老年代中没有引用的对象时 ...

  9. CMS收集器和G1收集器优缺点

    首先要知道 Stop the world的含义(网易面试):不管选择哪种GC算法,stop-the-world都是不可避免的.Stop-the-world意味着从应用中停下来并进入到GC执行过程中去. ...

随机推荐

  1. PHP制作的掷色子点数抽奖游戏实例

    PHP制作的掷色子点数抽奖游戏实例,通过掷色子点数来达到抽奖的效果,为抽奖活动增添一些趣味性. 我们将在html页面中写下如下的html结构代码,.wrap用来放置色子和提示信息,#prize则是用来 ...

  2. 【Angular】学习笔记-环境部署、项目建立相关

    Angular官网>搭建环境 首先要安装Node.js.官网>Download 一直next就好了. 安装node.js的目的是使用npm这些命令啦 然后这里推荐下载使用git SCM 也 ...

  3. WordPress疑难问题以及解决方案汇总

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/101 WordPress疑难问题以及解决方案汇总: 最近这 ...

  4. [20191112]oracle共享连接模式端口.txt

    [20191112]oracle共享连接模式端口.txt --//如果使用共享服务模式,你可以发现每次重启数据库对应的端口号会发生变化.# netstat -tunlp | egrep "A ...

  5. PHP代码篇(六)--如何根据邀请人id查询满足条件的会员上级

    说,如果有一个会员表,每一个会员都有一个邀请人from_id字段(记录该会员是谁邀请的),知道一个会员id,现在需要查询某一个会员是否是该会员的下级. 表如下: 一.当下需求 1.我们需要知道会员id ...

  6. Python语法速查: 1. 数据类型与内置函数

    返回目录 (1)常用内置数据类型 分类 类型名称 描述 数字 int 整数 float 浮点数 complex 复数 bool 布尔值 序列 str 字符串(不可变序列) list 列表 tuple ...

  7. Golang防止多个进程重复执行

    创建锁文件 lockFile := "./lock.pid" lock, err := os.Create(lockFile) if err != nil { log.Fatal( ...

  8. 迁移到MAC

    周末折腾了2天环境,主要是从windows迁移到mac上,提升逼格告别山寨,迈向专业化.首先,终于把pomelo的c客户端在xcode上跑起来了,至此已基本解决了网络连接问题.由于是第一次用mac开发 ...

  9. 【tf.keras】Resource exhausted: OOM when allocating tensor with shape [9216,4096] and type float on /job:localhost/replica:0/task:0/device:GPU:0 by allocator GPU_0_bfc

    运行以下类似代码: while True: inputs, outputs = get_AlexNet() model = tf.keras.Model(inputs=inputs, outputs= ...

  10. java 内存溢出总结

    堆 /** * jvm 参数: -Xms5m -Xmx5m -Xmn2m -XX:NewSize=1m * @author admin * */ public class HeapOutOfMemor ...