开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 30 天,点击查看活动详情
上几篇文章我们讲解了单线程垃圾收集器 Serial/SerialOld ,多线程垃圾收集器 Parallel Scavenge/Old, CMS标记清除垃圾收集器, 今天我们讲一下第四种通用垃圾收集器 G1垃圾收集器
垃圾收集器
- 新生代收集器: Serial、ParNew、Parallel Scavenge;
- 老年代收集器: Serial Old、CMS、Parallel Old;
- 通用收集器: G1;
收集器常用组合:
- Serial + Serial Old JVM设置-XX:+UseSerialGC
- Parallel Scavenge + Parallel Old JVM设置-XX:+UseParallelGC -XX:-UseParallelOldGC
- ParNew + CMS配合 JVM设置-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
- G1(不需要组合其他收集器) JVM设置-XX:+UseG1GC
收集器特点:
- Serial + Serial Old 单线程
- 单线程收集器,堆内存最小
- Parallel Scavenge + Parallel Old 吞吐量优先
- 吞吐量优先, 多线程收集
- 堆内存较大,多核cpu
- 新生代是eden/from/to 标记复制算法
- 老年代是标记+整理算法 减少碎片化
- Concurrent Mark Sweep 收集器 响应时间优先
- 配合PerNew 实际上就是Serial的多线程版本,该收集器采用复制算法回收内存,期间会STW
- 老年代CMS标记清除算法
- G1 Garbase-First 垃圾处理优先
- 从名字可知垃圾处理优先,哪里垃圾多,先处理哪里
- 基于 “标记-复制” 算法,收集后不会产生内存碎片
- 精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收
1. Garbage First收集器
什么样的场景适合我们采用G1垃圾收集器?
- 配备多核cpu及大容量内存的机器,适用内存6-8G以上的服务器
- 精准控制GC停顿时间,停顿时间是500ms以内
- 服务器需要满足高吞吐量的的性能
- 堆内存对象50%以上存活,对象分配和晋升的速度变化比较大
- 垃圾回收时间长,影响到系统响应时间
G1(Grabage-First)是一款面向服务端应用的垃圾收集器,JDK 9以后的默认垃圾回收器, 他是一个并行回收器,它把堆内存分割为很多不相关的区域(Region)物理上是不连续的,堆空间被分为若干个区域(Region),这些区域中包含了逻辑上的年轻代和老年代, G1堆内存的回收是以Region为基本单位的
上面我们说过G1垃圾收集器化整为零,把对内存分为大小相等的多个区域Region,对每一个Region都可以当作 新生代Eden区,Survivor区,老年代Old空间,收集器对于不同的区域Region采用不同的策略去处理,从而达到最好的收集效果
为什么说Region既可以是Eden,又可以是Survivor,又可以是老年代Old空间?因为这些区域都是逻辑上的概念区域,并不是真实的区域,之前的垃圾收集器会对堆物理连续分区,新生代/老年代,但是G1只会在逻辑上区分,他不要求整个Eden区,年轻代,老年代都是连续的,也不要求新生代和老年代都维持固定的大小,每个Region区可能既包含老年代,又包含年轻代,又包含大对象存储的Humongous区域
参数-XX:G1HeapRegionSize参数,可以设定Region的大小,一般来说只要超过Region容量一半的对象就可以判断为大对象,大对象一般都会存入Humongous 区域当作老年代来看待
2.G1垃圾回收过程
G1在进行垃圾收集的时候,会根据每个Region预计垃圾收集所需时间与预计回收内存大小的占比来选择对哪些Region区域进行回收
这种回收方式就不再有纯粹的Minor GC/Yong GC
和Major GC/Full GC
去回收某一块区域的分代对象,G1提供了三种垃圾回收方式,在不同的条件下被触发
- YoungGC 年轻代回收
- Mixed GC 混合回收的GC方式
- Full GC 整堆回收
2.1 YoungGC 年轻代回收
G1与之前垃圾收集器的Young GC有所不同,并不是当新生代的Eden区放满了就进行垃圾回收,G1会预估Eden区回收大概需要多久的时间,预估本次gc大概会回收多少内存来选择是否回收
- 预计回收时间远小于参数-XX:MaxGCPauseMills设定的值,那么G1就会增加年轻代的Region(可以从老年代或Humongous区划分Region给新生代),继续给新对象存放
- 直到下一次Eden区放满
- 如果G1计算回收时间接近参数-XX:MaxGCPauseMills设定的值,那么就会触发Young GC,开始进行垃圾回收
2.2 MixedGC 混合回收方式
G1的MixedGC 发生在老年代的空间达到一定的条件才触发
- 参数-XX:InitiatingHeapOccupancyPercent的值会定义老年代的堆空间内存占比,如果达到了这个值就会触发Mixed GC
- MixedGC 回收所有的新生代和部分老年代(根据用户设置的GC停顿时间来确定老年代垃圾收集的先后顺序)
- MixedGC 也会回收Humongous区,Humongous会存放大对象,大对象也是当作老年代来处理
- Mixed GC采用复制算法,需要把各个Region中存活的对象复制到另一个空闲的Region,如果在复制过程中发现没有足够的空Region放复制的对象,那么就会触发一次Full GC
2.3 FullGC 整堆回收
刚才我们说到 MixedGC 采用复制算法,如果你的空闲Region 不足以存放本次MixedGC 回收后还剩余的对象, 就会触发FullGC
- FullGC停止系统程序,然后采用单线程进行标记、清理和压缩整理算法回收垃圾
- 清理出部分Region区域来供下一次Mixed GC使用
- FullGC 非常耗时,对各个Region区域回收时,会涉及大量的跨区域引用的对象
- 跨区对象通过通过记忆集(卡表)方式记录,每个Region都要维护一个其他Region对自己内部对象的引用,Region中对象的可能被多个Region引用,所以G1的卡表实现要比CMS复杂很多
3.JVM参数配置
JVM开启G1配置可以通过-XX:+UserG1GC来配置
-verbose:gc -XX:+UseG1GC -Xms10M -Xmx10M -XX:+PrintGC -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:SurvivorRatio=8
下面我们详细讲解下G1垃圾收集器的JVM参数配置
JVM参数 | 参数描述 | |
---|---|---|
-XX:+UseG1GC | 开启使用G1垃圾收集器 | |
-XX:ParallelGCThreads | 指定GC工作收集垃圾并发的线程数量 | |
-XX:G1HeapRegionSize | 指定分区大小(1MB~32MB,必须2的N次幂),默认整堆划分2048个分区 | |
-XX:MaxGCPauseMillis | 指定目标最大停顿时间(默认200ms) | |
-XX:G1NewSizePercent | 新生代比例的设定数值的下限(默认整堆5%,新生代最小值比例) | |
-XX:G1MaxNewSizePercent | 新生代比例的设定数值上限下限(最大60%,值配置整数) | |
-XX:TargetSurvivorRatio | Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+年龄n的多个年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代 | |
-XX:MaxTenuringThreshold | 最大年龄阈值(默认15) | |
-XX:InitiatingHeapOccupancyPercent | 老年代占用空间达到整堆内存阈值(默认45%),Mixed GC周期结束后老年代使用率还是超过InitiatingHeapOccupancyPercent值,那么会再次触发全局并发标记过程,假如堆默认有100个region,如果有接近50个region都是老年代的region,50/100 > 45%的比例,则可能就要触发MixedGC了 | |
-XX:G1MixedGCLiveThresholdPercent | 默认为 65%,G1会优先回收垃圾多的内存分段。垃圾占内存分段比例越高的,越会被先回收。并且由一个阈值决定内存分段是否被回收 -XX:G1MixedGCLiveThresholdPercent, 默认65%,意思是垃圾占内存分段比例要达到 65% 才会被回收。如果垃圾占比太低,意味着存活的对象占比高,在复制的时候会花费更多的时间,就不会处理这个Region | |
-XX:G1MixedGCCountTarget | 在一次回收过程中指定做几次筛选回收(默认8次),并发标记结束以后,老年代中100%为垃圾的 region 就直接被回收了,仅部分为垃圾的region会被分成8次回收(可以通过 -XX:G1MixedGCCountTarget 设置,默认阈值8),所以 Mixed GC 的回收集(CSet)包括八分之一的老年代内存分段、Eden 区内存分段、Survivor 区内存分段 | |
-XX:G1HeapWastePercent | 默认值 10%,意思是允许整个堆内存有 10% 的空间浪费,意味着如果发现可以回收的垃圾占堆内存的比例低于10%,则不再进行混合回收,因为 GC 会花费很多的时间,但是回收到的内存却很少 |
这就是G1 垃圾收集器的基本原理和使用,我们这里只是讲解了基本的Region原理,分代收集,JVM参数等等,还有很多调优信息没了解,需要继续深入研究