CMS收集器:
全称:ConcurrentMarkSweep
cms垃圾回收器有时会发生并发失败的问题,这是它会采取补救措施,让老年代的的垃圾回收器,从cms并发垃圾回收器退化到SerialOld单线程垃圾回收器
垃圾回收过程
-
首先cpu开始并行执行,随后老年代发生
内存不足
-
当这些线程都到达了
安全点
,这时cms垃圾回收器会执行一个初始标记的动作
-
在执行初始标记时,会触发
stop the world
,其他的用户线程阻塞 -
等待初始标记完成以后,用户线程恢复运行,垃圾回收线程继续并发标记,把剩余的垃圾找出来,和用户线程并发执行,此过程响应时间很短
-
并发标记以后,进行
重新标记
,为了避免并发标记工作时用户线程也在工作,使现有对象发生变化,或是产生一些新的引用,对垃圾回收造成干扰,进行stop the world
-
重新标记以后,用户线程恢复运行,垃圾回收线程进行并发清理,
对标记对象进行回收
注意,在初始标记和重新标记阶段会造成STW(stop the world),其他时间都是并发执行的
=====================================================================
全称:
Garbage First
时间线
-
2004论文发布
-
2009JDK 6u14体验
-
2012JDK 7u4官方支持
-
2017JDK9默认
适用场景
-
同时注重
吞吐量(Throughput)
和低延迟(Low latency)
,默认的暂停时间是200 ms
-
超大堆内存,会将堆划分为多个大小相等的
Region
区域 -
整体上是
标记+整理算法
,两个区域之间是复制算法
// G1垃圾回收器的开关
-XX:+UseG1GC
// 所划分的Region区域内存大小:1 2 4 8 16
-XX:G1HeapRegionSize=size
// 垃圾回收最大停顿时间
-XX:MaxGCPauseMillis=time
===========================================================================
回收的三个阶段
- Young Collection:对新生代的垃圾收集,当老年代的内存超过
阈值
,进入下一阶段
- Young Collection+Concurrent Mark:对新生代的垃圾收集,同时执行一些并发标记
,进入下一阶段
-
Mixed Collection:对新生代,幸存区,老年代进行规模较大的收集
-
收集结束后,再次进入新生代的垃圾收集
⭐️1.4.1.1 Young Collection工作流程
============================================================================================
新生代内存布局
-
会STW
-
E:伊甸园
-
S:幸存区
-
O:老年代
当区域被占满,就会触发一次新生代的垃圾回收
将伊甸园中幸存的对象E以复制的算法,放入幸存区S
当幸存区的对象S较多,或者存活寿命超过阈值,此时又会触发新生代垃圾回收,幸存区的对象S有一部分会晋升到老年代O
⭐️1.4.1.2 Young Collection+Concurrent Mark
========================================================================================================
-
在Young GC时会进行GC Root的初始标记
-
老年代占用堆空间比例达到阈值时,进行并发标记(不会STW),由下面的JVM参数决定
-XX:InitiatingHeapOccupancyPercent=percent // 默认值45%
========================================================================================
会对E(伊甸园),S(幸存区),O(老年代)进行全面垃圾回收
-
最终标记(Remark)会STW
-
拷贝存活(Evacuation)会STW
// 用于指定GC最长的停顿时间
-XX:MaxGCPauseMillis=ms
混合收集阶段工作
伊甸园区(E)中的幸存对象会被复制算法复制到幸存区,另一些幸存区中的没有达到阈值的对象也会被复制算法复制到幸存区,另一些符合晋升条件的对象会被晋升到老年代区域
还有一些老年代中的无用的对象,复制算法会将幸存对象复制到新的老年代区域
为什么有的老年代被复制算法复制而有的没有呢?
设置最大暂停时间后,G1垃圾回收器会根据最大暂停时间去有选择的回收老年代中的有用对象,这样做也是为了避免耗时超出最大暂停时间。所有优先收集垃圾最多的区域
===============================================================================
-
Serial GC
-
新生代内存不足发生的垃圾收集 - minor gc
-
老年代内存不足发生的垃圾收集 - full gc
-
ParallelGC
-
新生代内存不足发生的垃圾收集 - minor gc
-
老年代内存不足发生的垃圾收集 - full gc
-
CMS
-
新生代内存不足发生的垃圾收集 - minor gc
-
老年代内存不足
-
G1
-
新生代内存不足发生的垃圾收集 - minor gc
-
老年代内存不足,根据阈值,达到对内存的45%时,触发并发标记以及混合收集阶段,如果回收速度比新产生垃圾速度要快,此时处于并发垃圾收集阶段,如果回收速度比新产生垃圾速度慢,就触发full gc
==========================================================================================
新生代回收的跨带引用(老年代引用新生代)问题
如果新生代对象的根对象有一部分来自于老年代,老年代的存活对象很多,如果去遍历整个老年代,去找根对象,效率会很低,因此我们采用卡表(card Table),把老年代区域再进行细分,分成一个个card,每一个card为512B,如果老年代其中有一个对象引用了新生代对象,那么对应的card就被标为“脏card”
这样我们遍历只需要关注脏card而不是整个老年代,这样减少搜索范围,提高扫描效率
我们以粉红色的区域为脏卡区域
-
卡表与Remembered Set
-
在引用变更时通过post-write barrier + dirty card queue
-
concurrent refinement threads 更新Remembered Set
==============================================================================
下图表示并发标记阶段时对象的处理状态,
-
黑色表示已经处理完成,并且有引用,在结束时会被保留下来
-
灰色为正在处理当中
-
白色为未处理对象
假如我们此时处理到了白色C对象,但是此时引用断了,C和B之间没有联系了
等待整个并发标记结束之后,C对象因为无引用,就会被当成垃圾回收掉
如果C被处理完标记为垃圾对象之后,并发标记还未结束,而用户线程改变了C的引用地址,A强引用了C
此时C已经被标记为垃圾对象,并且A已经处理完毕,所以不应该被回收的C就会被垃圾回收
为了避免此类问题的发生,我们要对对象的引用做进一步的检查,即Remark(重标记)阶段
进入重标记阶段
面试资料整理汇总
这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。
面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了
在这里祝大家能够拿到心仪的offer!
经处理完毕,所以不应该被回收的C就会被垃圾回收
为了避免此类问题的发生,我们要对对象的引用做进一步的检查,即Remark(重标记)阶段
进入重标记阶段
面试资料整理汇总
[外链图片转存中…(img-sWUaQZze-1720082091878)]
[外链图片转存中…(img-aYR5cGub-1720082091879)]
这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。
面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了
在这里祝大家能够拿到心仪的offer!