JVM垃圾收集器

原文地址:https://xeblog.cn/articles/24

image

新生代收集器

新生代均采用 复制 算法来回收内存。

Serial 收集器

最基本的、发展历史最悠久的单线程的收集器。在进行垃圾收集时,必须暂停其它所有的工作线程(Stop The World),直到它收集结束。它是 JVM 运行在 Client 模式下的默认新生代收集器,它比其它单线程的收集器更简单、更高效。可与 CMS 收集器 配合工作。

ParNew 收集器

Serial 收集器 的多线程版本。它是许多运行在 Server 模式下的虚拟机首选的新生代收集器,在使用 -XX:+UseConcMarkSweepGC 选项后的默认新生代收集器,也可以通过 -XX:+UseParNewGC 选项强制指定它。它除了是多线程收集之外,其它和 Serial 收集器 基本一样,它默认开启的收集线程数与 CPU 的数量相同,在 CPU 非常多的环境下,可通过 -XX:ParallelGCThreads 参数限制垃圾收集的线程数。可与 CMS 收集器 配合工作。

Parallel Scavenge 收集器

并行的多线程收集器,它的目标是达到一个可控的吞吐量(吞吐量是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值)。

 吞吐量 = 运行用户代码的时间 / (运行用户代码的时间 + 垃圾收集时间)

高吞吐量可以高效的利用 CPU 时间,尽快的完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。Parallel Scavenge 收集器 提供了两个参数用于精确控制吞吐量: -XX:MaxGCPauseMillis-XX:GCTimeRatio

最大垃圾收集停顿时间:-XX:MaxGCPauseMillis

允许一个大于0的毫秒数,收集器将尽可能保证内存回收花费时间不超过这个设定的值,它是以牺牲吞吐量和新生代空间来缩短 GC 停顿时间的。

吞吐量大小:-XX:GCTimeRatio

允许一个大于0且小于100的整数,垃圾收集时间占总时间的比率。

GC自适应调节参数:-XX:+UseAdaptiveSizePolicy

这是一个开关参数,当它打开后,就不需要手动指定新生代的大小(-Xmn),EdenSurvivor 区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量。

老年代收集器

老年代采用 标记-整理标记-清除 算法来回收内存。

Serial Old 收集器

它是 Serial 收集器 的老年代版本,也是一个单线程收集器,使用 标记-整理 算法。这个收集器的主要意义也是在于给 Client 模式下的虚拟机使用,如果是在 Server 模式下,那么它主要还有两大用途:

  • JDK1.5 以及之前版本中与 Parallel Scavenge 收集器 搭配使用。
  • 作为 CMS收集器 的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。

Parallel Old 收集器

它是 Parallel Scavenge 收集器 的老年代版本,使用多线程和 标记-整理 算法。

CMS 收集器 (Concurrent Mark Sweep)

它是一种并发的、以获取最短回收停顿时间为目标的收集器,使用 标记-清除 算法实现的。运行过程较为复杂,整个过程分为4个步骤:

  • 初始标记(CMS Initial Marking)
  • 并发标记(CMS Concurrent marking)
  • 重新标记(CMS ReMarking)
  • 并发清除(CMS Concurrent Sweep)

初始标记、重新标记仍需要暂停其它所有的工作线程,初始标记仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快。并发标记阶段就是进行 GC Roots 的可达性分析过程,而重新标记阶段则是为了修正并发标记期间因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。CMS 收集器 存在3个明显的缺点:

  • CMS收集器 会占用一部分线程而导致应用程序变慢,总吞吐量会降低。CMS 默认启功的回收线程数是(CPU数量 + 3)/ 4 ,相当于当 CPU 在4个以上时,并发回收时垃圾收集线程不少于 25%CPU 资源,并随着 CPU 数量的增加而下降。当 CPU 不足4个时,CMS 对用户线程的影响就可能变得更大。
  • CMS收集器 无法处理浮动垃圾,可能出现 Concurrent Mode Failure 失败而导致另一次 Full GC 的产生。由于 CMS 并发清除阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS 无法在当次收集中处理掉它们,只好留在下一次 GC 时再清理掉,这一部分垃圾就称为浮动垃圾。
  • 由于 CMS收集器 使用的是 标记-清除 算法,所以垃圾回收后会产生大量的空间碎片。CMS 提供 -XX:+UseCMSCompactAtFullCollection 的开关参数(默认开启),用于在 CMS 收集器顶不住要进行 Full GC 时开启内存碎片的合并整理过程,这个过程是无法并发执行的,虽然空间碎片没了,但是停顿时间不得不变长。

全干工程师:G1收集器

G1收集器 是当今收集器技术发展的最前沿成果之一。

上面所介绍的收集器,都只是负责 Java堆 中的一部分内存(新生代或老年代),而 G1 就不同了,它全干。
G1 将整个 Java堆 划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但是这两部分内存不再是物理隔离的,它们都是一部分不需要连续的 Region 的集合了。

具备的特点:

  • 并行与并发:G1 能充分利用多 CPU 、多核环境下的硬件优势,使用多个 CPU 来缩短 Stop The World 的停顿时间。
  • 分代收集(全干工程师):G1 可以不需要与其它收集器配合就能独立管理整个 GC堆,根据 分代收集 的概念采用不同的方式去处理。
  • 空间整合:基于 标记-整理复制 算法,不会产生内存空间碎片。
  • 可预测的停顿:G1 可以建立可预测的停顿时间模型,将垃圾收集消耗的时间限制在一定的时间内。

可预测的停顿时间模型

G1 之所以能够建立可预测的停顿时间模型,是因为它可以有计划的避免在整个 Java堆 中进行全区域的垃圾收集。G1 通过跟踪各个 Region 里面的内存堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先回收队列,每次根据允许的收集时间,优先回收价值最大的 Region。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限的时间内可以获取尽可能高的收集效率。

避免全堆扫描且保证准确性

G1 收集器中,Region 之间的对象引用以及其它收集器中的新生代与老年代之间的对象引用,虚拟机都是使用 Remembered Set 来避免全堆扫描的。G1 中的每一个 Region 都有一个与之对应的 Remembered Set,在对 Reference 类型的数据进行写操作的时间,虚拟机会产生一个屏障暂时中断写操作,然后检查这个引用的对象是否处于不同的 Region 之中,如果是,就会通过 CardTable 把相关引用信息记录到被引用对象所属的 RegionRemembered Set 中。当进行内存回收时,在 GC Roots 的枚举范围内加入 Remembered Set 即可保证不对全堆扫描也不会有遗漏。

G1运行过程

如果不计算维护 Remembered Set 的操作,G1 收集器的运行过程大致可以分为4个步骤:

  • 初始标记(G1 Initial Marking)
  • 并发标记(G1 Concurrent Marking)
  • 最终标记(G1 Final Marking)
  • 筛选回收(G1 Live Data Counting And Evacuation)

初始标记阶段只是简单的标记一下 GC Roots 能直接关联到的对象,并且修改TAMS(Next Top At Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的 Region 中创建新对象,这个阶段需要停顿线程,但耗时很短。并发标记阶段也是进行 GC Roots 的可达性分析过程,耗时很长但是可与用户程序一起工作。最终标记阶段是为了修正并发标记期间因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 中,这个阶段需要把 Remembered Set Logs 中的数据合并到 Remembered Set 里,需要停顿线程,但是可以并行执行。
最后的筛选回收阶段会对 Region 的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。

查看JVM所使用的收集器

java -XX:+PrintCommandLineFlags -version

在终端执行上述命令后,即可查看 JVM 所使用的收集器。

image

-XX:+UseParallelGC : 是虚拟机运行在 Server 模式下的默认值,打开此开关后,使用 Parallel Scavenge + Serial Old (PS MarkSweep) 的收集器组合进行内存回收。

参考

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

推荐阅读更多精彩内容