G1中的Young GC、Mixed GC、Full GC详解
⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记链接👉https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐
如果可以,麻烦各位看官顺手点个star~😊
文章目录
- [G1中的Young GC、Mixed GC、Full GC详解](#G1中的Young GC、Mixed GC、Full GC详解)
-
- [1 G1的GC模式](#1 G1的GC模式)
- [2 Young GC](#2 Young GC)
- [3 Mixed GC](#3 Mixed GC)
-
- [3.1 Mixed GC发生时机](#3.1 Mixed GC发生时机)
- [4 Full GC](#4 Full GC)
关于G1回收器的前置知识点:
1 G1的GC模式
G1提供了两种GC模式,Young GC和Mixed GC,两种都是完全Stop The World的。
- Young GC:选定所有年轻代里的Region。通过控制年轻代的region个数,即年轻代内存大小,来控制young GC的时间开销。
- Mixed GC:选定所有年轻代里的Region,外加根据Global concurrent marking统计得出收集收益高的若干老年代Region。在用户指定的开销目标范围内尽可能选择收益高的老年代Region。
由上面的描述可知,Mixed GC不是full GC ,它只能回收 部分 老年代的Region,如果mixed GC实在无法跟上程序分配内存的速度,导致老年代填满无法继续进行Mixed GC,就会使用serial old GC(full GC) 来收集整个GC heap。所以我们可以知道,G1是不提供full GC的。
2 Young GC
Young GC垃圾回收过程中,分为以下几种情况:
- 新创建对象(非巨大对象)分配到Eden区;
- Eden区对象转移到幸存区;
- 幸存区对象转移到另一幸存区;
- 幸存区对象转移到老年代;
用几张图片解释Young GC流程:
- 这里有 eden,survivor,old 还有个 free region,黄色为存活对象
- G1会把橙色对象拷贝到free region,或转移到幸存或老年代
- 当拷贝完毕,free region 就会晋升为 survivor region,以前的 eden 就被释放了
3 Mixed GC
Mixed GC会选取所有的 Young Region ➕ 收益高的若干个 Old Region。让我们回顾一下G1回收器工作过程(其实就是Mixed GC的过程),即我们上面一直提到的Global concurrent marking,一共分为四个步骤:
- 初始标记(initial mark,STW):它标记了从GC Root开始直接可达的对象。
- 并发标记(Concurrent Marking):这个阶段从GC Root开始对heap中的对象标记,标记线程与应用程序线程并行执行,并且收集各个Region的存活对象信息。
- 最终标记(Remark,STW):标记那些在并发标记阶段发生变化的对象,将被回收。
- 清除垃圾(Cleanup):清除空Region(没有存活对象的),加入到free list。
同时值得注意的是,对于第一阶段的初始标记,Mixed GC是共用了Young GC的SWT,这是因为他们可以复用root scan操作,所以可以说Global concurrent marking操作是伴随Young GC而发生的。
具体执行过程如下图所示:
同样的,被回收的 Region 就变回 Free Region 了,从上图可以看到 Mixed GC 只能回收部分的老年代。
G1 是如何选择要回收的 regions 的?
-XX:G1MaxNewSizePercent
与 Young GC关联;-XX:MixedGCCountTarget
与 Old GC关联;
-XX:MixedGCCountTarget
默认是8,意味着要在8次以内回收完所有的 Old Region
- 换句话说,如果对立有 800 个 old region, 那么一次Mixed gGC最大会回收 100 个 Old Region
G1 当然也可以被调整成不做这么多工作,也就是少回收,一定程度上浪费堆内存,导致更多的堆空间被使用
-XX:G1MixedGCLiveThresholdPercent
(默认:85) 可能会提高堆使用率-XX:G1HeapWastePercent
(默认:5) 如果可回收低于这个值, 那么将不会启动Mixed GC
3.1 Mixed GC发生时机
Young GC发生的时机大家都知道(文章开头已表明),那什么时候发生Mixed GC呢?其实是由一些参数控制着的,另外也控制着哪些老年代Region会被选入CSet。
G1HeapWastePercent
:在Global concurrent marking结束之后,我们可以知道老年代regions中有多少空间要被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是否达到此参数,只有达到了,下次才会发生Mixed GC;G1MixedGCLiveThresholdPercent
:老年代Region中的存活对象的占比,只有在此参数之下,才会被选入CSet。G1MixedGCCountTarget
:一次Global Concurrent marking之后,最多执行Mixed GC的次数;G1OldCSetRegionThresholdPercent
:一次Mixed GC中能被选入CSet的最多老年代 Region数量。
4 Full GC
由上面的描述可知,Mixed GC不是Full GC ,它只能回收部分老年代的Region,如果mixed GC实在无法跟上程序分配内存的速度,导致老年代填满无法继续进行Mixed GC,就会使用serial old GC(Full GC)来收集整个GC heap和方法区(元空间) 。所以我们可以知道,G1是没有 Full GC的机制的,G1 GC是使用的Serial Old GC的代码(后面被优化为多线程,但是速度相对来说依然比较慢),因此Full GC会暂停很久,因此在生产环境中,一定注意Full GC。
G1 Full GC
的原因一般有:
Mixed GC
赶不上内存分配的速度,只能通过Full GC
来释放内存,这种情况解决方案后面再说MetaSpace
不足,对于大量使用反射,动态代理的类,由于动态代理的每个类都会生成一个新的类,同时class
信息会存放在元空间,因此如果元空间不足,G1
会靠Full GC
来扩容元空间,这种情况解决方案就是扩大初始元空间大小。Humongous
分配失败,前面说过G1
分配大对象时,回收是靠Concurrent Marking
或Full GC
,因此如果大对象分配失败,则可能会引发Full GC