浅谈CMS和G1垃圾收集器
2023-02-10 13:34:59 16 举报
浅谈CMS和G1L集收集器
作者其他创作
大纲/内容
<b><font color="#b71c1c">CMS(Concurrent Mark Sweep)</font></b>收集器(-XX:+UseConcMarkSweepGC(old))
第一个实现让垃圾收集线程和用户线程同时工作的垃圾收集器
老年代采用<b><font color="#e74f4c">标记清除</font></b>算法
<b><font color="#e74f4c">运作流程</font></b>
<b>初始标记:</b>暂停所有的其他线程(STW),并记录下<b><font color="#e74f4c">GC root直接能引用</font></b>的对象,速度很快
<b>并发标记:</b>从GC root直接关联对象向下遍历对象,可以和用户线程一起<b>并发</b>运行
<b>重新标记:</b>修正并发标记期间,产生变动的那一部分对象的标记记录,<b>三色标记</b>中的<b><font color="#e74f4c">增量更新</font></b>算法
<b>并发清理:</b>开启用户线程,同时开始GC清理没有被标记的区域
<b>并发重置:</b>重置本次GC中标记的数据
<b><font color="#e74f4c">CMS优点</font></b>:
并发收集,低停顿
<b><font color="#e74f4c">CMS缺点:</font></b>
CMS收集器对<b>处理器资源</b>非常<b><font color="#e74f4c">敏感</font></b>,CMS默认启动的回收线程数是<b><font color="#e74f4c">(处理器核心数量+3)/4</font></b>,也就是说,如果处理器核心数在<b><font color="#e74f4c">四个或以上</font></b>,并发回收时垃圾收集线程只占用不超过25%的处理器运算资源,但是当处理器核心数量<b>不足<font color="#e74f4c">四个</font></b>时,<br>CMS对用户程序的影响就可能变得很大,处理器要分出一半的运算能力去执行收集器线程,<b>吞吐量</b>会大大降低。
<b><font color="#e74f4c">解决方案</font></b>:虚拟机提供了一种称为“<b>增量式并发收集器</b>”(Incremental Concurrent Mark Sweep/<b><font color="#e74f4c">i-CMS</font></b>)的CMS收集器变种,在并发标记、清理的时候让收集器线程、用户线程交替运行,尽量减少垃圾收集线程的独占资源的时间,<b>减少了对用户线程的影响</b>,但是<b>增加了垃圾回收的时间</b>,效果一般,<b>JDK9</b>发布后被废弃。
CMS无法处理<b><font color="#e74f4c">浮动垃圾</font></b>,执行过程中可能一边回收,一边再次触发full gc, 也就是<b><font color="#e74f4c">"concurrentmode failure"</font></b>,此时会进入stop the world,用<b>serial old</b>垃圾收集器来回收
<b><font color="#e74f4c">解决方案:</font></b>预留一部分空间供并发收集时的程序运作使用。在<b><font color="#e74f4c">JDK5</font></b>的默认设置下,CMS收集器当老年代使用了<b>68%</b>的空间后就会被激活,,可以适当调高参数<b><font color="#e74f4c">-XX:CMSInitiatingOccu-pancyFraction</font></b>的值来提高CMS的触发百分比,降低内存回收频率,获取更好的性能。到了<b>JDK 6</b>时,CMS收集器的启动阈值就已经默认提升至<font color="#e74f4c"><b>92%</b></font>。
<b><font color="#e74f4c">标记-清除算法</font></b>会产生大量的碎片
<b><font color="#e74f4c">解决方案:</font></b>然通过参数<b><font color="#e74f4c">-XX:+UseCMSCompactAtFullCollection</font></b>可以让jvm在执行完标记清除后再做整理
<b style="color: rgb(231, 79, 76);">G1</b><font color="#000000">收集器</font>(-XX:+UseG1GC)
面向服务器的垃圾收集器,主要针对配备大<b>容量内存</b>的机器,满足GC<b><font color="#e74f4c">停顿时间</font></b>要求,还需要具备<b>高吞吐量</b>性能特征
<b><font color="#e74f4c">G1收集器的运作流程</font></b>
<b>初始标记(initial mark,STW):</b>暂停所有的其他线程,并记录下gc roots直接能引用的对象,速度很快;
<b>并发标记(Concurrent Marking):</b>同<b>CMS的并发标记</b>
<b>最终标记(Remark,STW):</b>同<b>CMS的重新标记</b>
<b>筛选回收(Cleanup,STW):</b>筛选回收阶段首先对各个Region的<b>回收价值和成本</b>进行<b><font color="#e74f4c">排序</font></b>,根据用户所期望的GC<b>停顿时间</b>(可以用JVM参数<b><font color="#e74f4c"> -XX:MaxGCPauseMillis</font></b>指定)来制定回收计划
回收算法主要用的是<b><font color="#e74f4c">复制算法</font></b>,将一个region中的存活对象复制到另一个region中,这种不会像CMS那样回收完因为有很多内存碎片还需要整理一次,G1采用复制算法回收几乎不会有太多内存碎片
<b>G1垃圾收集分类</b>
<b><font color="#e74f4c">YoungGC:</font></b>回收时间远远小于参数<b><font color="#e74f4c"> -XX:MaxGCPauseMills</font></b> 设定的值,那么增加年轻代的region,<b>继续给新对象存放,不会马上做YoungGC</b>,直到下一次Eden区放满,G1计算回收时间接近参数<b><font color="#e74f4c"> -XX:MaxGCPauseMills </font></b>设定的值,那么就会触发Young GC
<b><font color="#e74f4c">MixedGC:不是FullGC</font></b>,老年代的堆占有率达到参数(<b><font color="#e74f4c">-XX:InitiatingHeapOccupancyPercent</font></b>)设定的值则触发,回收<b>所有的Young</b>和<b><font color="#e74f4c">部分Old</font></b>(根据期望的GC停顿时间确定old区垃圾收集的优先顺序)以及<b>大对象区</b>,主要使用复制算法,需要把各个region中存活的对象拷贝到别的region里去,拷贝过程中如果发现<b><font color="#e74f4c">没有足够的空region能够承载拷贝对象</font></b>就会触发一次<b>Full GC</b>
<b><font color="#e74f4c">Full GC:停止系统程序</font></b>,采用<b><font color="#e74f4c">单线程</font>进行标记、清理和压缩整理</b>,好空出来一批Region来供下一次MixedGC使用
<b><font color="#e74f4c">G1的优点:</font></b>
<b>并行与并发:</b>G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短StopThe-World停顿时间。
<b>分代收集</b>:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。
<b>空间整合:</b>G1从<b>整体</b>来看是基于<b><font color="#e74f4c">“标记整理”算法</font></b>实现的收集器;从<b>局部</b>上来看是基于<b><font color="#e74f4c">“复制”算法</font></b>实现的
<b>可预测的停顿:</b>G1 除了求低停顿外,还能建立<b>可预测</b>的<b>停顿时间模型</b>,能让使用者明确指定在一个长度为M毫秒的时间片段(通过参数<b><font color="#e74f4c">"-XX:MaxGCPauseMillis"</font></b>指定)内完成垃圾收集。
<b><font color="#e74f4c">G1缺点:</font></b>
G1使用<b>卡表</b>处理<b>跨代指针</b>实现更为复杂,堆中<b>每个Region</b>,无论扮演的是新生代还是老年代角色,都必须有<b>一份卡表</b>,这导致G1的记忆集(和其他内存消耗)可能会占整个堆容量的20%乃至更多的内存空间,由于G1对写屏障的复杂操作需要消耗更多的运算资源,G1就不得不将其实现为类似于<b>消息队列</b>的结构,把<b><font color="#e74f4c">写前屏障</font>和<font color="#e74f4c">写后屏障</font>中要做的事情都放到队列里</b>,然后再异步处理。
<b>解决方案:<font color="#e74f4c">大于8内存</font>使用G1垃圾收集器</b>
<b><font color="#e74f4c">为什么说8G以上应该用g1而不是用ParNew+CMS?</font></b><br>
这是由于ParNew+CMS是将内存分配为<b>年轻代和老年代</b>。只有当内存满了才会进行gc,使用8G以上的内存就会导致一次gc要清理的垃圾实在太多了,会导致CMS进行垃圾收集时,并发标记和并发清理的时间太长,用户线程也在同时进行,导致一次回收没有结束,再次触发fullGC,stw进行单线程回收
G1则将内存分成多个大小相等region块,使用复制算法,提升效率,在大内存的情况下,G1的记忆集合其他内存消耗,占领堆的比例也会降低,还能建立可预测的停顿时间模型,控制垃圾回收的时间
0 条评论
下一页