浅谈 Minor GC,Marjor GC,Full GC 的触发机制
1. 前言
对于 JVM 的运行时数据区域,又被细分成好几块内存区域,其中 堆和非堆,是垃圾回收管理的主要区域;而为了更好的进行垃圾回收,又将堆内部划分为几个区域,从而实行分代收集机制
本文主要介绍了 Minor GC,Marjor GC,Full GC 会在什么条件下触发,以及这几种 GC 主要发生的区域
附 GC 触发流程:
2. 堆与非堆
JKD 1.8 堆与方法区:
说到垃圾的分类,就不得不提一下堆空间了,这里是垃圾回收管理的主要区域
- 新生代:新对象和没达到一定年龄的对象都在新生代,而新生代又分为以下几个区
- Eden:初次创建的对象都放在 Eden 区,也就是伊甸园区
- Survivor 0:幸存者零区,在 Eden 区经历过一次炮火洗礼的精神小伙会进入之类
- Survivor 1:在幸存者零区经历炮火洗礼的帅小伙会进入幸存者一区
- 老年代:被长时间使用的对象,年龄到了以后会进入老年代,老年代的内存空间应该要比年轻代更大,在这里很少发生 GC,如果在老年代经常触发 GC,就要考虑程序写的是不是有问题,或者要进行 JVM 的调优
至于非堆,也就是 JVM 规范定义的方法区,在 Full GC 的时候是会涉及到方法区的
3. Minor GC
Minor GC 也称 Yong GC,因为其主要收集的内存区域就是新生代
Minor GC 的触发机制:Minor GC 的触发是被动的,当程序不断的创建新对象,JVM 会往 Eden 区塞,当 Eden 区内存空间满了的时候,就会触发 Minor GC,需要注意的是,Survivor 0 满不会触发 Minor GC
那 S0 的对象什么时候垃圾回收呢?
假设 Survivor 0 现在是满的,此时又触发了 Minor GC ,发现 Survivor 0 依旧是满的,存不下,此时会将 S0 区与Eden 区的对象一起进行可达性分析,找出活跃的对象,将它复制到 S1 区并且将S0区域和 Eden 区的对象给清空,这样那些不可达的对象进行清除,并且将S0 区 和 S1区交换
这里又引出一个问题,为啥会有两个 Survivor 区?
答案是如果只有一个 Survivor 区 那么就无法实现对于 S0 区的垃圾收集,以及分代年龄的提升
由于 Java 对象大多短命,所以 Minor GC 会非常的频繁,但由于 Eden 较小,所以其速度还是比较快的
需要注意的是,Minor GC 会引发 STW(Stop The World),STW 是指 GC 事件发生的过程中,会产生应用程序的停顿,停顿产生时整个应用程序线程都会被暂停,没有任何响应,这个停顿称为 STW;在这个阶段,全局停顿,所有 Java 代码停止,Native 代码可以执行,但不能与 JVM 交互;这些现象多半是由于 GC 引起
4. Major GC 与 Full GC
Major GC 又称 Old GC,因为其主要收集的内存区域是老年代
老年代的空间一般比新生代要大,这里发生的 GC 次数理当且应当比较少,为什么呢?
-
Major GC 触发机制:当老年代空间不足时,会先尝试触发 Major GC,如果空间还是不足,则触发 Major GC
-
Major GC 的速度比 Minor GC 慢十倍以上,STW 的时间会更长
-
如果 Major GC 后,内存还是不足,就会触发 OOM
而对于 Full GC,覆盖了整个堆空间,包括方法区,其触发的情况有五种:
- 调用
System.gc()
方法,但不是必然执行,可以理解为建议执行 - 老年代空间不足,新来的对象老年代放不下了
- 方法区空间不足
- 通过 Minor GC 后进入老年代的平均大小大于老年代可用内存
- 由 Eden 区、S0 区向 S1 复制的对象太大了,导致直接进入老年代,但是老年代内存不够
5. 总结
了解垃圾回收的触发机制对于我们平时监控 JVM 的性能、处理 JVM 的调优、排查 OOM 异常,都有很大的帮助
转载自:https://juejin.cn/post/6998527815964426271