JVM的三种常见GC:Minor GCMajor GC与Full GC

Posted 流楚丶格念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM的三种常见GC:Minor GCMajor GC与Full GC相关的知识,希望对你有一定的参考价值。

文章目录

JVM的GC

GC:垃圾回收

GC英文全称为Garbage Collection,即垃圾回收。

Java中的GC就是对内存的GC。

Java的内存管理实际上就是对象的管理,其中包括对象的分配和释放

Java对象的分配,程序员可以通过new关键字,Class的new-Instance方法等来显示的分配;而对象的释放,程序员不能实时的进行释放,这就需要GC来完成。

JVM GC的种类

JVM常见的GC包括三种:Minor GC,Major GC与Full GC

针对HotSpot VM的实现,它里面的GC按照回收区域又分为两大种类型:

  • 一种是部分收集(Partial GC)
  • 一种是整堆收集(Full GC)

部分收集(Partial GC):不是完整收集整个Java堆的垃圾收集,其中又分为:

  • 新生代收集(Minor GC/Young GC):只是新生代的垃圾收集
  • 老年代收集(Major GC/Old GC):只是老年代的垃圾收集
  • 混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集,目前,只有G1 GC会有这种行为

整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集

注意:JVM在进行GC时,并非每次都对所有区域(新生代,老年代,方法区)一起回收的,大部分时候回收的都是指新生代

GC的触发机制

年轻代GC(Minor GC)触发机制

触发机制:

  • 当年轻代空间不足时,就会触发Minor GC这里的年轻代空间不足指的是Eden区满,Survivor区满不会触发GC(每次Minor GC 会清理年轻代的内存)

因为Java对象大多具备朝生夕死的特新,所以Minor GC非常频繁,一般回收速度也比较快.
Minor GC会引发STW,暂停其他用户线程,等垃圾回收结束,用户线程才恢复运行

老年代GC(Major GC/Full GC)触发机制

指发生在老年代的GC,对象从老年代消失时,我们说"Major GC或Full GC"发生了、

一般出现Major GC,经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)

触发机制:

  • 也就是老年代空间不足时,会先尝试触发Minor GC,如果之后空间还不足,则触发Major GC

PS:
Major GC的速度一般会比Minor GC慢10倍以上,STW的时间更长
如果Major GC后,内存还不足,就报OOM了
Major GC的速度一般会比Minor GC慢10倍以上

Full GC触发机制

触发Full GC执行的情况有如下五种:

  • 调用System.gc(),系统建议执行Full GC,但是不必然执行
  • 老年代空间不足
  • 方法区空间不足
  • 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
  • 由Eden区,from区向to区复制时,对象大小大于to区可用内存,则把对象转存到老年代,并且老年代的可用内存小于该对象大小(那要是GC之后还不够呢?那还用说:OOM异常送上)

另外要特别注意: full GC是开发或调优中尽量要避免的

为什么需要把Java堆分代?

经研究,不同对象的生命周期不同,70%-99%的对象是临时对象

其实不分代完全可以,分代的唯一理由就是优化GC性能,如果没有分代,那所有的对象都在一个区域,当需要进行GC的时候就需要把所有的对象都进行遍历,GC的时候会暂停用户线程,那么这样的话,就非常消耗性能,然而大部分对象都是朝生夕死的,何不把活得久的朝生夕死的对象进行分代呢,这样的话,只需要对这些朝生夕死的对象进行回收就行了.总之,容易死的区域频繁回收,不容易死的区域减少回收.

扩展:分代回收机制的三个假说

当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”(GenerationalCollection)[插图]的理论进行设计,分代收集名为理论,实质是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上:

  1. 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的
  2. 强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡

这两个分代假说共同奠定了多款常用的垃圾收集器的一致的设计原则:收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄(年龄即对象熬过垃圾收集过程的次数)分配到不同的区域之中存储。

把分代收集理论具体放到现在的商用Java虚拟机里,设计者一般至少会把Java堆划分为新生代(Young Generation)和老年代(Old Generation)两个区域。顾名思义,在新生代中,每次垃圾收集时都发现有大批对象死去,而每次回收后存活的少量对象,将会逐步晋升到老年代中存放。

分代收集并非只是简单划分一下内存区域那么容易,它至少存在一个明显的困难:对象不是孤立的,对象之间会存在跨代引用。

假如要现在进行一次只局限于新生代区域内的收集,但新生代中的对象是完全有可能被老年代所引用的,为了找出该区域中的存活对象,不得不在固定的GC Roots之外,再额外遍历整个老年代中所有对象来确保可达性分析结果的正确性,反过来也是一样。遍历整个老年代所有对象的方案虽然理论上可行,但无疑会为内存回收带来很大的性能负担。

为了解决这个问题,就需要对分代收集理论添加第三条经验法则:

  1. 跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数

依据这条假说,我们就不应再为了少量的跨代引用去扫描整个老年代,也不必浪费空间专门记录每一个对象是否存在及存在哪些跨代引用,只需在新生代上建立一个全局的数据结构(称为“记忆集”,RememberedSet),这个结构把老年代划分成若干小块,标识出老年代的哪一块内存会存在跨代引用。此后当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入到GC Roots进行扫描。

所以说,虽然这种方法需要在对象改变引用关系(如将自己或者某个属性赋值)时维护记录数据的正确性,会增加一些运行时的开销,但比起收集时扫描整个老年代来说仍然是划算的。

以上是关于JVM的三种常见GC:Minor GCMajor GC与Full GC的主要内容,如果未能解决你的问题,请参考以下文章

直通BAT JVM必考题:Minor GCMajor GCFull GC的区别

直通BAT JVM必考题:Minor GCMajor GCFull GC的区别

Minor GC(Young GC)Full GCMajor GCOld GC

Java GC工作原理以及Minor GCMajor GCFull GC简单总结

gc之四--Minor GCMajor GC和Full GC之间的区别

Minor GCYoung GCOld GCMajor GCMixed GCFull GC都是什么?