简介
大家经常会看到各种各样的 GC 名称,比如:Minor GC、Young GC、Full GC、Old GC、Major GC、Mixed GC。
刚开始看到这么多 GC 名词后,真的是心累
哎,没办法,一声国粹之后也只能慢慢的把它们理理顺。
GC分类
我们现在先对其进行逐一分类:
-
partial GC: 代表局部垃圾回收,可以有如下细分:
- young GC(Minor GC): 指的是对新生代区域垃圾回收
- old GC:指的是收集老年代,只有 CMS 的 concurrent collection是这个模式
- Mixed GC:收集整个新生代,和部分老年代,只有G1有这个模式
-
Full GC:收集整个过程,包括新生代、老年代、永久代(JDK8之前)
-
Major GC:可以是指 old GC 也可以是指 Full GC。这是因为JVM规范没有对这些名词有具体的定义,时间久了后就使用混乱了。所以如果讨论 Major GC 的时候需要指定前提到底是讨论的是 old GC 还是 Full GC,比如周志明版的《深入理解虚拟机》就把 old GC 统称为 【Major GC / Full GC】更加不做区分了,这里我们先按照 old GC == Major GC 讨论
对象分配
这里我们先回顾一下虚拟机堆内存图:
首先对象一般都是在新生代中分配的,而且是在 Eden 区中。
一些大对象,比如数组,长字符串等会在老年代中分配,虚拟机提供了一个 -XX:PretenureSize 参数,如果对象大于这个设置的值就直接在老年代分配。
长期存活的对象将进入老年代,这里指的是当 Eden 区达到一定的比例后不能创建新对象,则触发垃圾回收(young GC),将无用对象清理掉,然后剩余对象复制到某个 Survivor1(S1) 中,同时清空Eden区。 当Eden区再次满了,会再次将 Eden 中的不能清空的对象存到另外一个 Survivor2(S2), 同时将S1区中的不能清空的对象,也复制到S2中,保证Eden和S1,均被清空。 重复多次(默认15次)Survivor中没有被清理的对象,则会复制到老年代Old(Tenured) 区中。对于晋升老年代的年龄阈值可以用 -XX:MaxTenuringThreshold 设置。
触发young GC
由于对象一般情况下是直接在新生代中的 Eden 区进行分配,如果Eden区域没有足够的空间,那么就会触发young GC(Minor GC)。因为 Java 对象大多数具备朝生夕死的特性,所以 young GC(Minor GC)会非常频繁,回收速度也非常快。
触发Full GC
Full GC 相对于 Minor GC 来说,停止用户线程的 STW(stop the world)时间过长,至少慢10倍以上,所以要尽量避免,首先说一下Full GC可能产生的原因,接着给出排查方法以及解决策略。
在代码中调用System.gc()方法会建议JVM进行Full GC,但是注意这只是建议,JVM执行不执行是另外一回事儿,不过在大多数情况下会增加Full GC的次数,导致系统性能下降,一般建议不要手动进行此方法的调用,可以通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。
在YGC之前,会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间。如果小于,说明YGC是不安全的,则会查看参数 HandlePromotionFailure 是否被设置成了允许担保失败,如果不允许则直接触发Full GC;如果允许,那么会进一步检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果小于也会触发 Full GC
Metaspace(元空间)在空间不足时会进行扩容,当扩容到了-XX:MetaspaceSize 参数的指定值时,也会触发FGC
Major GC/Old GC
老年代会在两种情况下触发 Old GC:一是开启分配担保机制,根据历次 Minor GC 后进入老年代的对象大于当前老年代内存大小,判断 Minor GC 有风险,则会触发 Old GC;二是 Minor GC 后剩余对象太多,老年代放不下了也会触发 Old GC。
Mixed GC
Mixed GC是G1中特有的概念,当老年代内存占据到了45%就户触发Mixed GC,对新生代和老年代都进行回收。
好了今天就到这,之后会单独讨论 G1 收集器和 CMS 收集器。
作者:码小刀
链接:https://juejin.cn/post/7085174576950280200
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。