JVM04——七个GC垃圾收集器,一个都不能少

了解了JVM内存区域与垃圾回收算法,今天将为各位带来关于垃圾收集器的知识。关注我的公众号「Java面典」了解更多 Java 相关知识点。

Java 堆内存被划分为新生代和老年代两部分,因此 JVM 通常采用分代回收算法。新生代主要使用复制和标记-清除垃圾回收算法 ,老年代主要使用标记-整理垃圾回收算法。JVM 中针对新生代和年老代分别提供了多种不同的垃圾收集器。

根据线程特点,可以将收集器分为三类:

  1. 串行收集器:Serial 收集器、Serial Old 收集器;
// 串行收集器开启方式
-XX:+UseSerialGC
  1. 并行收集器:Parallel Scavenge 收集器、Parallel Old 收集器、ParNew 收集器;
// 并行收集器开启方式
-XX:+UseSerialGC
  1. 并发收集器:CMS 收集器、G1 收集器。
// CMS 收集器开启方式
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC

// G1 收集器开启方式
-XX:+UseG1GC

Serial 收集器

  • 新生代:Serial 垃圾收集器是 JVM 运行在 Client 模式下默认的新生代垃圾收集器;
  • 复制算法 :Serial 是最基本垃圾收集器,使用复制算法,曾经是 JDK1.3.1 之前新生代唯一的垃圾收集器;
  • 单线程:Serial 只会使用一个 CPU 或一条线程去完成垃圾收集工作;
  • 线程暂停:Serial 在进行垃圾收集的时,必须暂停其他所有的工作线程,直到垃圾收集结束;
  • 单线程效率最高:Serial 对于限定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率。

ParNew 收集器

  • 新生代:ParNew 垃圾收集器是很多 JVM 运行在 Server 模式下新生代的默认垃圾收集器;
  • 复制算法 : ParNew 和 Serial 一样使用了复制算法;
  • 多线程 :ParNew 垃圾收集器其实是 Serial 收集器的多线程版本;
  • 线程暂停:ParNew 和 Serial 一样垃圾收集的同时,必须暂停其他所有的工作线程;
  • 默认线程数:ParNew 收集器默认开启和 CPU 数目相同的线程数,可以通过-XX:ParallelGCThreads 参数来限制垃圾收集器的线程数。

Parallel Scavenge 收集器

  • 新生代:Parallel Scavenge 收集器也是一个新生代垃圾收集器;
  • 复制算法:Parallel Scavenge 收集器同样使用复制算法;
  • 多线程 :Parallel Scavenge 收集器也是一个多线程的垃圾收集器;
  • 高吞吐量:Parallel Scavenge 重点关注的是程序达到一个可控制的吞吐量(Thoughput,吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)),高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务;
  • 适用场景:主要适用于在后台运算而不需要太多交互的任务。自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个重要区别。

新生代 Parallel Scavenge 收集器与 ParNew 收集器工作原理类似:

  1. 都是多线程的收集器;
  2. 都使用的是复制算法;
  3. 在垃圾收集过程中都需要暂停所有的工作线程。

Serial Old 收集器

  • 老年代:Serial Old 是 Serial 垃圾收集器老年代的版本;
  • 标记-整理算法:Serial Old 使用标记-整理算法;
  • 单线程:Serial Old 与 Serial 一样是单线程收集器;
  • Client 模式:JVM 运行在 Client 模式下,Serial Old 是默认的老年代垃圾收集器;
  • Server 模式:JVM 运行在 Server 模式下,Serial Old 主要有两个用途:
  1. 在 JDK1.5 之前版本中与新生代的 Parallel Scavenge 收集器搭配使用;
  2. 作为年老代中使用 CMS 收集器的后备垃圾收集方案。

新生代 Serial 与年老代 Serial Old 搭配垃圾收集过程图:

Serial 与 Serial Old.png

新生代 Parallel Scavenge/ParNew 与年老代 Serial Old 搭配垃圾收集过程图:

Parallel Scavenge/ParNew 与 Serial Old .png

Parallel Old 收集器

  • 老年代:Parallel Old 收集器是 Parallel Scavenge 的老年代版本;
  • 标记-整理算法:Parallel Old 收集器使用标记-整理算法;
  • 多线程:Parallel Old 收集器是多线程收集器;
  • 高吞吐量:Parallel Old 是能够为老年代提供吞吐量优先的垃圾收集器;
  • JDK1.6:Parallel Old 是 JDK1.6才开始提供的。

在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只能保证新生代的吞吐量优先,无法保证整体的吞吐量。如果系统对吞吐量要求比较高,可以优先考虑新生代 Parallel Scavenge 和老年代 Parallel Old 收集器搭配使用。

新生代 Parallel Scavenge 和年老代 Parallel Old 收集器搭配运行过程图:

Parallel Scavenge 和 Parallel Old.png

CMS 收集器

  • 老年代:CMS(Concurrent mark sweep)收集器是一种年老代垃圾收集器;
  • 标记-清理算法:和其他年老代使用标记-整理算法,CMS 使用标记-清除算法;
  • 多线程 :CMS 采用的是多线程并发的标记-清除算法;
  • 停顿时间端: CMS最主要目标是获取最短垃圾回收停顿时间,最短的垃圾收集停顿时间可以为交互比较高的程序提高用户体验。
CMS收集器.png

CMS 运行过程分为以下 4 个阶段:

  1. 初始标记:标记 GC Roots 能直接关联的对象(速度很快,需要暂停所有的工作线程);
  2. 并发标记:进行 GC Roots 跟踪(和用户线程一起工作,不需要暂停工作线程);
  3. 重新标记:修正因用户程序继续运行而导致标记产生变动的那一部分对象的标记(需要暂停所有的工作线程);
  4. 并发清除:清除 GC Roots 不可达对象(和用户线程一起工作,不需要暂停工作线程)。

由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行。

G1 收集器

特点

  • 无分代:G1 将新生代,老年代的物理空间划分取消了。这样我们再也不用单独的空间对每个代进行设置了,不用担心每个代内存是否足够;
  • 标记-整理算法:G1 收集器采用标记-整理算法,无内存碎片产生;
  • 分区回收:G1 虽然没有了新生代与老年代的物理限制,但是 G1 采取内存分区策略,将堆内存划分为大小固定的几个独立区域。在分区中,同时存在新生代与老年代;

分区

G1分区内存模型.png

新生代区域:G1 收集器中新生代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者 Survivor 空间;
老年代区域:G1 收集器通过将对象从一个区域复制到另外一个区域,以此来完成老年代的清理工作;
Humongous区域:巨型对象区域。如果一个对象占用的空间超过了分区容量 50% 以上,G1 收集器就认为这是一个巨型对象。这些巨型对象,默认直接会被分配在年老代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。为了解决这个问题,G1 划分了一个 Humongous 区,它用来专门存放巨型对象。如果一个 H 区装不下一个巨型对象,那么 G1 会寻找连续的 H 分区来存储。为了能找到连续的 H 区,有时候不得不启动 Full GC。

对象分配策略

说起大对象的分配,我们不得不谈谈对象的分配策略。它分为3个阶段:

  1. TLAB(Thread Local Allocation Buffer)线程本地分配缓冲区
  2. Eden区中分配
  3. Humongous区分配

TLAB为线程本地分配缓冲区,它的目的为了使对象尽可能快的分配出来。如果对象在一个共享的空间中分配,我们需要采用一些同步机制来管理这些空间内的空闲空间指针。在Eden空间中,每一个线程都有一个固定的分区用于分配对象,即一个TLAB。分配对象时,线程之间不再需要进行任何的同步。

对TLAB空间中无法分配的对象,JVM会尝试在Eden空间中进行分配。如果Eden空间无法容纳该对象,就只能在老年代中进行分配空间。

最后,G1提供了两种GC模式,Young GC和Mixed GC,两种都是Stop The World(STW)的。下面我们将分别介绍一下这2种模式。

G1 Young GC

Young GC 主要是对 Eden 区进行 GC ,它在 Eden 空间耗尽时会被触发。在这种情况下,Eden 空间的数据移动到 Survivor 空间中,如果 Survivor 空间不够,Eden 空间的部分数据会直接晋升到年老代空间。Survivor 区的数据移动到新的 Survivor 区中,也有部分数据晋升到老年代空间中。最终 Eden 空间的数据为空,GC 停止工作,应用线程继续执行。

G1 Young GC 阶段:

  1. 根扫描:静态和本地对象被扫描;
  2. 更新RS: 处理 Dirty Card 队列更新 RS(Remembered Set,作用是跟踪指向某个 Heap 区内的对象引用);
  3. 处理RS: 检测从年轻代指向年老代的对象;
  4. 对象拷贝:拷贝存活的对象到 Survivor/Old 区域;
  5. 处理引用队列: 软引用,弱引用,虚引用处理。

G1 Mix GC

Mix GC不仅进行正常的新生代垃圾收集,同时也回收部分后台扫描线程标记的老年代分区。

G1 Mix GC运行步骤:

  1. 全局并发标记(global concurrent marking)
    1.1. 初始标记(initial mark,STW):在此阶段,G1 GC 对根进行标记。该阶段与常规的 (STW) 年轻代垃圾回收密切相关;
    1.2. 根区域扫描(root region scan):G1 GC 在初始标记的存活区扫描对老年代的引用,并标记被引用的对象。该阶段与应用程序(非 STW)同时运行,并且只有完成该阶段后,才能开始下一次 STW 年轻代垃圾回收;
    1.3. 并发标记(Concurrent Marking):G1 GC 在整个堆中查找可访问的(存活的)对象。该阶段与应用程序同时运行,可以被 STW 年轻代垃圾回收中断;
    1.4. 最终标记(Remark,STW): 该阶段是 STW 回收,帮助完成标记周期。G1 GC 清空 SATB 缓冲区,跟踪未被访问的存活对象,并执行引用处理;
    1.5. 清除垃圾(Cleanup,STW):在这个最后阶段,G1 GC 执行统计和 RSet 净化的 STW 操作。在统计期间,G1 GC 会识别完全空闲的区域和可供进行混合垃圾回收的区域。清理阶段在将空白区域重置并返回到空闲列表时为部分并发。

  2. 拷贝存活对象(evacuation)

G1 收集器与 CMS 收集器相比,G1 收集器两个最突出的改进是:

  1. 基于标记-整理算法,不产生内存碎片;
  2. 可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收。
// G1 收集器参数设置
-XX:+UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200
// -XX:+UseG1GC —— 为开启G1垃圾收集器,
// -Xmx32g —— 设计堆内存的最大内存为32G,
// -XX:MaxGCPauseMillis=200 —— 设置GC的最大暂停时间为200ms

JVM系列推荐

JVM03——四种垃圾回收算法,你都了解了哪几种

JVM02——JVM运行时内存

JVM01——JVM内存区域的构成

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容