阅读 220

浅谈 Minor GC,Marjor GC,Full GC 的触发机制

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

1. 前言

对于 JVM 的运行时数据区域,又被细分成好几块内存区域,其中 堆和非堆,是垃圾回收管理的主要区域;而为了更好的进行垃圾回收,又将堆内部划分为几个区域,从而实行分代收集机制

本文主要介绍了 Minor GC,Marjor GC,Full GC 会在什么条件下触发,以及这几种 GC 主要发生的区域

附 GC 触发流程:

image.png


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,覆盖了整个堆空间,包括方法区,其触发的情况有五种

  1. 调用 System.gc() 方法,但不是必然执行,可以理解为建议执行
  2. 老年代空间不足,新来的对象老年代放不下了
  3. 方法区空间不足
  4. 通过 Minor GC 后进入老年代的平均大小大于老年代可用内存
  5. 由 Eden 区、S0 区向 S1 复制的对象太大了,导致直接进入老年代,但是老年代内存不够

5. 总结

了解垃圾回收的触发机制对于我们平时监控 JVM 的性能、处理 JVM 的调优、排查 OOM 异常,都有很大的帮助

文章分类
后端
文章标签