垃圾收集器与内存分配策略 -- 垃圾收集器

之前谈到的所有算法都是内存回收的理论基础,而现在我们来谈谈关于内存回收的具体实现。

垃圾收集器分为七种:Serial 收集器,ParNew 收集器,Parallel Scavenge 收集器,Serial Old 收集器,Parallel Old 收集器,CMS 收集器,G1 收集器。

下图展现了这七种作用于不同分代的垃圾收集器,存在连线代表可以搭配使用。

垃圾收集器

接下来我们依次了解一下各垃圾收集器。

(1)Serial收集器
最基本的,发展历史最悠久的单线程垃圾收集器,曾是(JDK1.3之前)虚拟机新生代收集器唯一选择。因简单高效(相对于其它的单线程收集器),没有多余的线程开销,在Client模式下是一个非常好的选择。

缺点:在它工作时必须暂停其它所有的线程(服务暂停),直到Serial收集器将所有垃圾收集完成,因此可能会产生较长的等待时间。

新生代、老年代使用串行回收;新生代复制算法、老年代标记-整理算法。

参数控制: -XX:+UseSerialGC 指定使用Serial垃圾收集器

Serial收集器运行示意图

Serial收集器.png

(2)ParNew收集器
Serial收集器的多线程版本,其余行为都与Serial收集器完全一致,两者其实共用了大量相同的代码。除了Serial收集器外,唯一一个能与CMS收集器配合工作的收集器,在Server模式下的虚拟机中首选的新生代收集器。ParNew收集器在单CPU的环境中绝对不会比Serial收集器有更好的效果。

ParNew收集器运行示意图大致一样

ParNew收集器.png

参数控制:
-XX:+UseParNewGC 强制指定ParNew收集器
-XX:ParallelGCThreads 限制线程数量

(3)Parallel Scaveng收集器
新生代收集器,也是复制算法的收集器,且还是并行的多线程收集器。其他的垃圾回收器都是关注如何缩短在垃圾回收时用户线程的等待时间,而Parallel Scavenge收集器则是关注系统吞吐量:吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)。吞吐量越高越能代表高效率的利用CPU,因此也被称为“吞吐量优先”收集器。

Parallel Scavenge收集器与ParNew收集器的主要区别是前者拥有GC自适应的调节策略(GC Ergonomics),由参数-XX:+UserAdaptiveSizePolicy控制。

参数控制:
-XX:+UseParallelGC:使用Parallel收集器+ 老年代串行
-XX:MaxGCPauseMillis:最大垃圾回收停顿时间,一个大于0的毫秒数。该值不是越小越好,GC停顿时间是以牺牲吞吐量与新生代空间换取的。
-XX:GCTimeRatio:直接设置吞吐量大小,大于0小于100的整数,垃圾回收时间占总时间的比率,相当于吞吐量的倒数,比如设置为9,那么就是1/(1+9),最大GC时间就占总时间的10%。
-XX:+UserAdaptiveSizePolicy:开关参数,开启后就会自动根据系统当前的性能信息,动态调整新生代大小,Eden和Survivor比例,晋升老年代对象大小等参数。

Parallel Scaveng收集器运行示意图

Parallel Scaveng收集器.png

(4)Serial Old收集器
作为Serial收集器的老年代版本,同样是一个单线程收集器,主要给Client模式下的虚拟机使用,在Server模式下有两大用途:①在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用;②作为CMS收集器的备选方案,在并发收集发生 Concurrent Mode Failure 时使用。

Serial Old收集器运行示意图

Serial Old收集器.png

(5)Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。这个收集器是在JDK 1.6中才开始提供。在注重吞吐量与CPU资源敏感的场合,都可以优先考虑 Parallel Scavenge收集器加Parallel Old收集器的组合

参数控制: -XX:+UseParallelOldGC 使用Parallel收集器+ 老年代并行

Parallel Old收集器运行示意图

Parallel Old 收集器.png

(6)CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以牺牲吞吐量为代价获取最短回收停顿时间为目标的收集器。在重视服务的响应速度,希望系统停顿时间最短的情况下使用该收集器是最佳的选择。CMS是用于对年老代的回收,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。

CMS收集器是基于“标记-清除”算法实现的,CMS收集器的GC周期由6个阶段组成。其中4个阶段与实际的应用程序是并发执行的,而其他2个阶段需要暂停应用程序线程。:
①初始标记(CMS initial mark):执行时必须暂停其他一切线程(官方称为:Stop The World),仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。

②并发标记(CMS concurrent mark):这个动作发生在进行GC Roots Tracing的过程中,紧随初始标记阶段,耗时较长,但由于应用程序的线程和并发标记的线程并发执行,所以用户不会感觉到停顿。

③并发预清理(CMS concurrent precleaning):在并发标记阶段可能有新进入老年代的对象,并发预清理就是查找这些新对象以减少下一步的负担。

④重新标记(CMS remark):执行时也必须暂停其他一切线程。为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。

⑤并发清除(CMS concurrent sweep):清理垃圾对象,这个阶段收集器线程和应用程序线程并发执行,耗时较长。

⑥并发重置(CMS concurrent reset):重置CMS收集器的数据结构,等待下一次的垃圾回收执行。

CMS收集器运行示意图

CMS收集器

优点:并发收集,低停顿

缺点:
①对CPU资源非常敏感,在并发阶段可能会导致系统吞吐量下降。
②在CMS并发清理阶段用户线程也在运行,用户线程就会产生新的垃圾,这部分垃圾在被标记后会被延迟到下一次GC时才被清理掉,这一部分垃圾就叫做“浮动垃圾”。在CMS收集器会预留一部分空间给用户线程使用,当预留空间不足时就会导致“Concurrent Mode Failure”失败。所以当CMS收集器无法处理浮动垃圾时,空间不足可能导致“Concurrent Mode Failure”失败而导致另一次的 Full GC的产生。
③CMS收集器是基于“标记-清除”算法实现的,所以收集结束时可能会产生大量的空间碎片,可以通过参数设置碎片整理。

参数
-XX:+UseConcMarkSweepGC:使用CMS收集器
– XX:CMSInitiatingOccupancyFraction =n :CMS收集器的启动阀值,该值代表老年代空间已使用的比例。该值太高可能会导致无法预留足够的空间给用户线程,从而导致“Concurrent Mode Failure”失败。
-XX:+ UseCMSCompactAtFullCollection:Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理
-XX:ParallelCMSThreads 设定CMS的线程数量(一般情况约等于可用CPU数量)

(7)G1收集器
面向服务端应用的,基于“标记-整理”算法实现的垃圾收集器,在JDK1.7u4版本及以后才作为正式的商用,在未来准备替换掉JDK1.5中发布的CMS收集器。
与其他收集器相比,G1具备以下优势:
①并行与并发:通过多核与多CPU优势,缩短系统停顿时间,且不影响Java程序的执行。
②分代收集:G1不需要与其他收集器配合就能独立管理整个GC堆。
③空间整合:不会产生空间碎片。
④可预测的停顿:区别于CMS,G1最大的优势就是可以系统停顿时间可控可预测。

对垃圾收集器的总结

不再将老年代与新生代进行物理隔离,而是将堆规划为大小相等的独立区域(Region)划分内存空间。根据垃圾的堆积的价值大小,G1会在后台维护一个优先列表,优先回收垃圾价值最大的区域。

G1收集器的步骤分为以下四个步骤:
①初始标记(Initial Mark):执行时必须暂停其他一切线程(官方称为:Stop The World),标记一下GC Roots能直接关联到的对象,并且修改TAMS值,让下一阶段用户程序并发执行时能够在正确的区域进行创建对象,执行速度很快。

②并发标记(Concurrent Marking):从GC Roots开始对堆中对象进行可达性分析,耗时间长,但可以与用户线程并发执行。

③最终标记(Final Marking):执行时也必须暂停其他一切线程。为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。

④筛选回收(Live Data Counting and Evacuation):对各个区域(Region)的回收价值与成本排序,然后根据用户指定的GC停顿时间来制定回收计划。

参数
-XX:+UseG1GC :启动GC收集器
-XX:G1HeapRegionSize : 设定堆中区域(Region)的大小,大小区间只能是2的幂次方

对垃圾收集器的总结

垃圾收集器综合对比.png

参考文章:https://mp.weixin.qq.com/s?__biz=MzI4NDY5Mjc1Mg==&mid=2247483952&idx=1&sn=ea12792a9b7c67baddfaf425d8272d33&chksm=ebf6da4fdc815359869107a4acd15538b3596ba006b4005b216688b69372650dbd18c0184643&scene=21#wechat_redirect

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

推荐阅读更多精彩内容