CMS收集器存在哪些缺点
1、只适用于老年代,采用标记清除算法,实现GC和用户线程同时执行,减少STW时间
2、标记清除算法会产生大量碎片化问题
3、存放大对象会直接晋升到老年代,如果不频繁使用,会非常浪费堆内存空间
4、大对象很容易造成fullgc,所有工作线程会触发STW问题,导致工作线程阻塞。
什么是G1收集器
1.G1是一个并行/并发回收器,它把堆内存分割为很多不相关的区域(Region) (物理上不连续的)。
使用不同的Region来表示Eden、幸存者0(S0)区,幸存者(S1)1区,老年代等。
2.侧重点在于回收垃圾最大量的区间(Region),所以我们给G1一个名字:垃圾优先(Garbage First) 。
3.G1 GC有计划地避免在整个Java 堆中进行全区域的垃圾收集。
G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。
G1垃圾回收器的目标:可配置在N毫秒内最多只占用M毫秒的时间进行垃圾回收,全部复制算法。
垃圾回收核心原理
1.使用Rset找关联关系【跨带引用关联】
在一个region中可能会引入到其他的region,为了避免不需要的全局扫描,在每个region中都对应一个Remembered Set(记忆集),使用CarTable
记录每个region区相互引用的关系。
![](https://img.haomeiwen.com/i25147367/80389418203ef384.png)
2.使用cset表里可回收的空间(可能20%、50%和100%等),把尽可能回收完的空间进行回收。
Collection Set(CSet)记录了GC要收集的Region集合,集合里的Region可以是任意年代的
候选老年代分区的CSet准入条件,可以通过活跃度阈值-XX:G1MixedGCLiveThresholdPercent(默认85%)进行设置,从而拦截那些回收开销巨大的对象;
每次混合收集可以包含候选老年代分区,可根据CSet对堆的总大小占比-XX:G1OldCSetRegionThresholdPercent(默认10%)设置数量上限。
由上述可知,G1的收集都是根据CSet进行操作的,年轻代收集与混合收集没有明显的不同
3.使用写屏障确保新生代对象被老年代对象引用的时候不被gc
写屏障,其实就是指在赋值操作前后,加入一些处理(可以参考AOP的概念):记录赋值的操作。
老年代存活对象多时,每次minor gc查询老年代所有对象影响gc效率(因为gc stop-the-world),所以在老年代有一个write barrier(写屏障)来管理的card table(卡表),card table存放了所有老年代对象对新生代对象的引用。
所以每次minor gc通过查询card table来避免查询整个老年代,以此来提高gc性能
Heap信息:
garbage-first heap total 570368K, used 307771K [0x00000006c0000000, 0x00000006c0101168, 0x00000007c0000000)
region size 1024K, 2 young (2048K), 1 survivors (1024K)
Metaspace used 3129K, capacity 4568K, committed 4864K, reserved 1056768K
class space used 337K, capacity 392K, committed 512K, reserved 1048576K
G1收集器特色
1.并行与并发
并行:在主线程暂停的情况下,使用并行收集
G1收集器在回收时,可以实现多个GC线程同时执行 利用CPU多核利用率,但是会让用户线程暂停 触发stw机制。
并发:在主线程运行的情况下,使用并发收集
多个GC与用户线程用时执行,用户线程不会阻塞。
2.分代收集原理
G1收集器,也会分为新生代eden、S0或者S1区域,但是不要求整个eden、S0或者S1区域具有连续性。
![](https://img.haomeiwen.com/i25147367/b28f8efbc49663c6.png)
一个region(分区)只能属于一个角色,有可能为eden区、S区、老年代等, E表示为Eden区、S区表示为S1,S0区,老年代O区 空白的表示为未使用的分配的内存。H区存放巨型对象
巨型对象设计原理:
a、一个对象大于region的一半时,称之为巨型对象,会专门弄一个H区存放巨型对象
b、如果一个H区装不下的情况下,则会寻找连续H区存储
c、如果还没有足够的空间,有可能会引发FULLGC.
d、回收时会优先回收
2.0垃圾回收顺序:
young gc(新生代) 一> young gc + concurrent mark(新生代+并发标) 一> Mixed GC(混合回收)顺序,进行垃圾回收
![]()
2.1YoungGC(新生代)回收
使用标记复制算法,将还有引用的对象清理到新的S区,然后清空原有所有的E和S区。
![](https://img.haomeiwen.com/i25147367/7c0edd3dbf057334.png)
2.2young gc + concurrent mark(新生代+并发标)回收
- 初始标记:标记GCroot对象,还会标记我们的region(块)
- 标记Region:根据我们rset 找到对应和rootRegion相关的region块进行标识
- 并发标记:遍历所有的rootRegion引用的所有的区标记我们所有的可达对象(不会STW,jvm配置参数-XX:InitiatingHeapOccupancyPercen=45%)
- 重新标记:同CMS一样,只不过G1中采用了比CMS更快的初始快照算法:snapshot一at一the一beginning (SATB)。
- 清理:清理采用的是复制算法。这里清理只会选取垃圾较多的region
2.3MixGC(混合)回收(图形参考CMS)
回收整个Young Region(新生代区域),部分的老年代区域,如果G1无法有足够的空间复制对象的时候,有可能会引发FullGc
3.空间整合
之前我们所学习的CMS收集器采用标记清除算法,容易产生碎片化的问题且空间不连续性,而G1收集器划分成n多个不同的采用标记压缩算法,没有产生碎片化的问题。分配大对象的时候,避免FullGC的问题,所以如果堆内存空间比较大,使用G1收集器更加有优势。
4.可预测的停顿时间模型
能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。
由于G1收集器采用分区模型,所以G1可以只选取部分区域进行内存回收,这样缩小了回收的范围,因此对于全局停顿情况的发生也能得到较好的控制。G1跟踪各个Region 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。
5.局限性
最多支持2048块,每块大小在1-32M,内存需要配置在2G-64G。
内存配置至少在2G以上,小内存的话发挥不了功效,还不如使用CMS回收器。
参数设置
选项和默认值 | 描述 |
---|---|
-XX:+UseG1GC | 使用垃圾优先(G1)收集器 |
-XX:MaxGCPauseMillis = n | 设置期望达到的最大Gc停顿时间指标 ,默认值是200ms |
-XX:InitiatingHeapOccupancyPercent = n | 启动并发GC周期的(整个)堆占用百分比。GC使用它来触发GC,该GC基于整个堆的占用来触发并发GC周期,而不仅仅是世代之一(例如,G1)。值为0表示“进行恒定的GC循环”。默认值为45。 |
-XX:NewRatio = n | 新旧大小比例。预设值为2。 |
-XX:SurvivorRatio = n | 伊甸园/幸存者空间大小之比。预设值为8。 |
-XX:MaxTenuringThreshold = n | 任职期限的最大值。预设值为15。 |
-XX:ParallelGCThreads = n | 设置垃圾回收线程数 最大设置为8 |
-XX:ConcGCThreads = n | 设置并发标记的线程数。将n设置为并行垃圾回收线程数(ParallelGCThreads)的1/4左右。 |
-XX:G1ReservePercent = n | 设置保留为虚假上限的堆数量,以减少升级失败的可能性。预设值为10。 |
-XX:G1HeapRegionSize = n | 使用G1,Java堆可细分为大小一致的区域。这将设置各个细分的大小。该参数的默认值是根据堆大小按人机工程学确定的。最小值为1Mb,最大值为32Mb。 |
网友评论