发布于2022-12-03 09:00 阅读(617) 评论(0) 点赞(20) 收藏(0)
链接: JVM垃圾收集—垃圾收集算法
上一篇介绍了垃圾收集算法及分区,这篇我们来学习垃圾收集器
串行收集器 Serial 和 Serial Old
只能有一个垃圾回收线程执行,用户线程暂停。(适用于内存较小的嵌入式设备)
并行收集器[吞吐量优先] Paraller Scanvenge、Parallel Old
多条垃圾收集线程并行工作,但此时用户线程仍然处于等待阶段。(适用于科学计算、后台处理等若干交互场景)
并发收集器[停顿时间优先] CMS、G1
用户线程和垃圾收集线程同时执行(但并不一定是并行的,可能是交替执行的),垃圾收集线程在执行的时候不会停顿用户线程的运行。(适用于相对时间有要求的场景,比如WEB)
我按照发展顺序给大家介绍一下:
特点:它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更重要的是其在垃圾收集的时候需要暂停其他线程。
优点:简单高效
缺点:收集过程需要暂停所有线程。
应用:Client模式下的默认新生代收集器(Serial收集器是最基本、发展历史最悠久的收集,之前(JDK1.3.1之前)是虚拟机新生代收集器的唯一选择。)
特点:ParNew收集器实质上是Serial收集器的多线程并行版本,除了同时使用多条线程进行垃圾收集之外,其余的行为包括Serial收集器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX: PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、对象分配规 则、回收策略等都与Serial收集器完全一致,在实现上这两种收集器也共用了相当多的代码。
优点:多CPU时,比Serial效率更高。
缺点:收集过程暂停所有的应用程序,单CPU核心时比Serial效率差。
应用:运行在Server模式下的虚拟机中首选的新生代收集器。
此收集器与吞吐量关系密切,故也称为吞吐量优先收集器。
特点:多线程
Parallel Scavenge收集器使用两个参数控制吞吐量:
控制最大的垃圾收集停顿时间 XX:MaxGCPauseMillis
直接设置吞吐量的大小 XX:GCTimeRatio
吞吐量 = 运行用户代码时间 / 运行用户代码时间 + 运行垃圾收集时间。
如果虚拟机完成某个任务,用户代码加上垃圾收集器总共耗时100分钟,其中垃圾收集器花费了1分钟,那吞吐量就是 99 / 100= 99%。
吞吐量越大,意味着垃圾收集的时间更短、则用户代码可以充分利用CPU资源,尽快完成程序的运算任务。
这里不是你设置了就一定有效,虚拟机会尽可能的靠近你设置的数值,并不是绝对一致
Serial Old 是Serial 收集器的老年代版本
特点:多线程,采用标记-整理算法。
应用场景:注重高吞吐量以及CPU资源敏感的场合
是一种以获取最短回收停顿时间为目标的收集器
应用场景:适用于注重服务的响应速度,希望系统停顿时间最短,给用户带来良好的体验。比如web服务,b/s结构。
工作分为四步:
第一步、初始标记(STW),标记GC Roots能直接关联到的对象,速度非常快。
第二步、并发标记,进行GC Roots Tracing ,就是从GC Roots开始找到它能引用的所有对象的过程。
第三步、重新标记(STW),为了修成并发标记期间因用户程序继续运作导致标记产生变动的一部分对象的标记记录。这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间要短。
第四步、并发清除,在整个过程中耗时最长的并发标记和并发清除过程,收集器线程都可以与用户线程一起工作,因此,从总体上看,CMS收集器的内存回收过程与用户线程一起并发执行的
优点:并发收集、并发清除、低停顿。
缺点:对CPU要求高,无法处理浮动垃圾、产生大量空间碎片、并发阶段会降低吞吐量。
这里有一个刁钻的面试问题:
CMS默认晋升老年代为6的原因: 简单来说,CMS对内存尤其敏感,且会导致单线程Serial FullGC 这个是非常严重的后果,而从结果上说越大的MaxTenuringThreshold会更快的导致heap的碎片化(不光old 区,首先要明白对于内存的分配并不是真的一个对象一个对象紧密排列的),所以历代CMS 默认这个值都会比较小(JDK8以前是4,之后调整为6)
工作也是分为四步:
第一步、初始标记(STW),标记GC Roots能直接关联到的对象(速度很快)。
第二步、并发标记,进行 GC Roots Tracing,就是从GC Roots开始找到它能引用的所有其他对象的过程。
第三步、最终标记(STW),为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分的标记记录。这个阶段的停顿时间一般会比初始标记阶段稍微长,但是要比并发标记要短。
第四步、筛选回收(STW),对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间指定回收计划。
G1 总结:
JDK 7 开始使用,JDK8非常成熟,JDK9默认的垃圾收集器。
如果停顿时间过短,会造成频繁垃圾回收,会导致OOM:GC overhead limitexceeded (超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常)
虚拟机怎么判断是否需要使用G1收集器?
答:50%以上的堆被存活对象占用、对象分配和晋升的速度变化非常大、垃圾回收时间较长。
停顿时间 = 垃圾收集器进行垃圾回收的执行时间
吞吐量 = 运行用户代码时间 / 运行用户代码时间 + 运行垃圾收集时间。
如果虚拟机完成某个任务,用户代码加上垃圾收集器总共耗时100分钟,其中垃圾收集器花费了1分钟,那吞吐量就是 99 / 100= 99%。
吞吐量越大,意味着垃圾收集的时间更短、则用户代码可以充分利用CPU资源,尽快完成程序的运算任务。
停顿时间越短就越适合需要和用户交互的程序,良好的响应速度能提升用户体验; 高吞吐量则可以高效地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不 需要太多交互的任务。
吞吐量和停顿时间是衡量垃圾回收器的标准,我们进行调优也是观察这两个变量。
这个准则只能参考,因为性能取决于堆的大小,应用程序维护的实时数据量以及可用处理器的数量和速度。
大白话:牛逼哄哄的硬件设备不怎么需要调优,垃圾设备才考验你的调优技能。
如果应用程序的内存在100M左右,使用串行收集器 -XX:+UseSerialGC。
如果是单核心,并且没有停顿要求,默认收集器,或者选择带有选项的-XX:+UseSerialGC
如果允许停顿时间超过1秒或者更长时间,默认收集器,或者选择并行-XX:+UseParallelGC
如果响应时间最重要,并且不能超过1秒,使用并发收集器 -XX:+UseConcMarkSweepGC or -XX:+UseG1GC
1.8默认的垃圾回收:PS + ParallelOld
作者:狗蛋来了
链接:http://www.javaheidong.com/blog/article/582786/1090cf6a9e19c79c828e/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!