JVM的垃圾收集器

总览

image.png

处于不同区域的垃圾收集器负责该区域(年轻代、老年代)的收集工作。有连线的表示可以搭配使用

Serial收集器

Serial收集器是一个单线程的垃圾收集器,这里的单线程强调的是进行立即收集时,其他线程必须暂停(stop the world)。运行如下:但该收集器是所有收集中额外耗费内存(memory Footprint 指的是保证垃圾收集器能够顺利高效的进行而存储的额外信息)最小的。


image.png

ParNew收集器

ParNew其实是Serial的多线程并行版本,除了Serial之外,目前只有它能配合CMS工作,其工作流程如图所示:


image.png

它默认开启的收集线程数与处理器核心数量相同。在这种多核处理器的条件下,效率自然高于serial收集器。这里解释一下垃圾收集中常常混淆的并发和并行两个概念。

  • 并发:并发描述的是垃圾收集线程和用户线程之间的关系,表示同一时间有多条垃圾收集线程在工作
  • 并行:并行描述的是多个垃圾收集之间的关系,说明同一时间,垃圾线程和用户线程都在运行

Parallel Scavenge收集器

Parallel Scavenge收集器跟ParNew很相似,不同点在于该收集器更关注可控制的吞吐量,吞吐量指的是:


image.png

Parallel Scavenge通过以下两个参数精确控制吞吐量:

  • -XX: MaxGCPauseMillis 最大垃圾收集停顿时间
  • -XX: GCTimeRatio 吞吐量大小
    -XX: MaxGCPauseMillis是一个大于0的毫秒数,当然不能指望设置的越小越好,收集器只会尽可能的完成这个目标,同时花费时间减少是通过牺牲年轻代内存大小和吞吐量完成的。导致垃圾收集更频繁,吞吐量下降。
    除此之外,Parallel Scavenge收集器还有一个参数值得关注:
  • -XX:+UseAdaptiveSizePolicy
    该参数被激活后,表示不需要人工指定新生代的大小(-Xmn)、Eden和Survivor区的比例(-XX:SurvivoRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数 虚拟机会动态调整以提供最合适的停顿时间和吞吐量。

Serial Old收集器

Serial Old收集器是Serial的老年代版本,同样是单线程收集器,使用标记-整理算法,用途如下:

  • 在客户端模式下,供HotSpot虚拟机使用
  • 服务端模式下,在Jdk5之前与Parallel Scavenge搭配使用,另一种是作为CMS收集器的失败后备预案。


    image.png

Parallel Old收集器

Parallel Old是Parallel Scavenge的老年代版本,多线程,标记整理算法,两者搭配使用,成为名副其实的“吞吐量优先”的搭配组合。在吞吐量和资源稀缺的场合,可以优先考虑该搭配组合。


image.png

CMS收集器

CMS收集器是一种旨在获取最短停顿时间的垃圾收集器,运作过程包含以下四个步骤:

  • 初始标记
  • 并发标记
  • 重新标记
  • 并发清除
    其中初始标记和重新标记是需要暂停用户线程的,并发标记和并发清除是和用户线程一起执行的,执行流程图如下所示:


    image.png

    虽然CMS收集器是一个低停顿、并发收集的收集器,但还是存在以下缺点:

  • CMS默认启动的回收线程数是(处理器核心数量+3) /4, 也就是说, 如果处理器核心数在四个或以上, 并发回收时垃圾收集线程只占用不超过25%的处理器运算资源, 并且会随着处理器核心数量的增加而下降。 但是当处理器核心数量不足四个时,CMS对用户程序的影响就可能变得很大
  • 浮动垃圾
    浮动垃圾是指在CMS收集的并发标记和并发清理过程中、由于是和用户线程一起运行的,用户线程就会不断产生新的垃圾对象,而这些对象又是在垃圾收集后出现的。CMS收集器只能在下次垃圾收集时才能进行回收,这一部分被称为“浮动垃圾”。同时不同于其他收集器可以等到老年代满了才进行垃圾回收,CMS是并发的,因此要预留空间给程序运行使用。所以通过-XX: CMSInitiatingOccupancyFraction参数设置触发CMS收集的老年代空间占用比例。但是这个参数调的过高可能会引起Concurrent Mode Failure,表示CMS预留的空间不足于程序新分配的对象,此时CMS会启动后备方案,通过Serial OLd收集器进行老年代回收
  • 空间碎片化 因为CMS收集器是采用的标记-清除算法

Garbage First收集器

开创了面向局部收集的设计思路和基于Region的内存布局形式,是一款面向服务端的收集器,从JDK9开始,替代了Parallel Scavenge搭配Parallel Old的收集器,成为服务端默认的垃圾收集器。
G1不再坚持固定大小以及固定数量的分代区域划分, 而是把连续的Java堆划分为多个大小相等的独立区域(Region) , 每一个Region都可以根据需要, 扮演新生代的Eden空间、 Survivor空间, 或者老年代空间。
G1收集器中虽然还是存在新生代、老年代,但是不再是固定的,而是不需要连续的动态集合,它将Region作为最小的回收单元,每个Region可以通过-XX:G1HeapRegionSize设置大小,Region中包含一个Humongous区域,存储大对象,对于超过Region一半大小的对象就存放在N个连续的Region的Humongous区域。
G1的收集思路是跟踪每个Region的垃圾收集价值大小,即回收所获得的空间大小和回收所需时间的经验值,维护一个优先级列表,回收时优先回收价值大的。

image.png

G1缺点:

  • 需要为每一个Region维护一个卡表 内存占用较高
  • 执行负载高

Shenandoah收集器

Shenandoah收集器对比G1有所改进,例如:

  • 支持并发回收 ,G1虽然可以多线程执行回收但是不能和用户线程并发执行
  • Shenandoah不支持分代收集
  • 摒弃记忆集 使用连接矩阵记录跨Region的引用关系
    image.png

    该收集器大致分为以下9个阶段:
    1.初始标记 标记与GC Roots直接关联的对象 需暂停用户线程
    2.并发标记 与G1一样, 遍历对象图, 标记出全部可达的对象
    3.最终标记 处理剩余的SATB扫描, 并在这个阶段统计出回收价值
    最高的Region, 将这些Region构成一组回收集 需暂停用户线程
    4.并发清理 清理那些整个区域内连一个存活对象都没有找到
    的Region
    5.并发回收 Shenandoah要把回收集里面的存活对象先复制一份到其他未被使用的Region之中,通过转发指针“Brooks Pointers”实现对象移动后 原本指向这些对象的引用的改变
    6.初始引用更新 并发回收阶段复制对象结束后, 还需要把堆中所有指向旧对象的引用修正到复制后的新地址 暂停用户线程 引用更新的初始化阶段实际上并未做什么具体的处理, 设立这个阶段只是为了建立一个线程集合点, 确保所有并发回收阶段中进行的收
    集器线程都已完成分配给它们的对象移动任务而已

    7.并发引用更新 真正开始进行引用更新操作
    8.最终引用更新 解决了堆中的引用更新后, 还要修正存在于GC Roots中的引用 暂停用户线程
    9.并发清理

转发指针 Brooks pointer

image.png

原有对象布局结构的最前面统一增加一个新的引用字段, 在正常不处于并发移动的情况下, 该引用指向对象自己

ZGC收集器

ZGC收集器是一款基于Region内存布局的, (暂时)不设分代的, 使用了读屏障、 染色指针和内存多重映射等技术来实现可并发的标记-整理算法的, 以低延迟为首要目标的一款垃圾收集器。
ZGC虽然也是基于Region收集,但其将Region划分为了大、中、小3类容量

image.png

大型Region存放的是4Mb及以上大小的对象,容量不固定,每个Region只存放一个大型对象,同时该Region中的对象不会重分配
染色指针
ZGC收集器采用染色指针使得一旦某个Region的存活对象被移走之后, 这个Region立即就能够被释放和重用掉, 而不必等待整个堆中所有指向该Region的引用都被修正后才能清理。
ZGC分为以下四个阶段:
1.并发标记
与G1、 Shenandoah不同的是, ZGC的标记是在指针上而不是在对象上进行的
2.并发预备重分配
根据特定的查询条件统计得出本次收集过程要清理哪些Region, 将这些Region组成重分配集(Relocation Set)
3.并发重分配
重分配是ZGC执行过程中的核心阶段, 这个过程要把重分配集中的存活对象复制到新的Region上, 并为重分配集中的每个Region维护一个转发表(ForwardTable) , 记录从旧对象到新对象的转向关系
4.并发重映射
重映射所做的就是修正整个堆中指向重分配集中旧对象的所有引用

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

推荐阅读更多精彩内容

  • 上一篇JVM垃圾收集器与内存分配策略(一),下面是jdk1.7版本的垃圾收集器之间的关系,其中连线两端的两种垃圾收...
    零点145阅读 266评论 0 0
  • 如果说收集算法是内存回收的方法论,那垃圾收集器就是内存回收的实践者。《Java虚拟机规范》中对垃圾收集器应该如何实...
    tracy_668阅读 405评论 0 0
  • 今天这篇文章本来要写LinkedList的,为了准备面试最近在看垃圾收集器。临时变成介绍垃圾收集器啦,这篇文章会有...
    带鱼真好吃阅读 1,711评论 2 3
  • Serial收集器内容精讲 简介:serial垃圾收集器讲解 hashMap list,hashcode 是什么?...
    日落_3d9f阅读 124评论 0 1
  • 背景:看完《深入理解Java虚拟机》和相关博客,对JVM还是没有一个条理清晰的认识,遂提取了书中相关知识点和参考相...
    LandHu阅读 1,181评论 0 1