FullGC和YoungGC

the sun is shining on a mountain range

想知道什么是FullGC的话,首先要了解,GC是什么?

GC是什么?

GC是垃圾收集(Gabage Collection),为什么需要GC呢?是因为与C或C++不同,java不需要人为地手动维护内存,所以,jvm提供gc回收机制来回收jvm自认为不会使用或者需要移动区的对象。

GC的原理是什么?

当对象创建的时候,GC就开始监控这个对象的地址、大小以及使用情况。

通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过判断对象是否可达,来回收对象。如果GC判断该对象不可达,则回收内存空间。

可以手动执行System.gc()手动gc。

GC中的新生代、老年代

image-20240531155835538

上方的Eden、s0、s1都属于新生代。

大部分情况下,对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,并且对象的年龄还会加 1(Eden 区->Survivor 区后对象的初始年龄变为 1),当它的年龄增加到一定程度(默认为大于 15 岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置默认值,这个值会在虚拟机运行过程中进行调整,可以通过-XX:+PrintTenuringDistribution来打印出当次 GC 后的 Threshold。

经过这次 GC 后,Eden 区和”From”区已经被清空。这个时候,”From”和”To”会交换他们的角色,也就是新的”To”就是上次 GC 前的“From”,新的”From”就是上次 GC 前的”To”。不管怎样,都会保证名为 To 的 Survivor 区域是空的。Minor GC 会一直重复这样的过程,在这个过程中,有可能当次 Minor GC 后,Survivor 的”From”区域空间不够用,有一些还达不到进入老年代条件的实例放不下,则放不下的部分会提前进入老年代。

大对象会直接进老年代,大对象的定义:需要占用连续的内存,比如数组、集合等。

Young GC(Minor GC)

新生代的GC,当新生代的Eden区满了之后,就会触发Young GC,也叫Minor GC

Full GC(Major GC)

顾名思义,Full GC发生在老年代。触发的条件:

  1. 当老年代没有足够空间存放对象时,触发
  2. 如果元空间区域的内存达到了设定的阈值 -XX:MetaspaceSize=,也会触发
  3. 显示调用System.gc或Runtime.gc()
  4. 老年代可用内存小于新生代全部对象的大小,如果没开启空间担保参数,会直接触发Full GC,所以一般空间担保参数都会打开。
  5. 老年代可用内存小于历次新生代GC后进入老年代的平均对象大小,此时会提前Full GC;但是”-XX:HandlePromotionFailure”参数,在JDK 1.6以后就被废弃了,所以现在一般都不会在生产环境里设置这个参数了。在JDK 1.6以后,只要判断”老年代可用空间”大于”新生代对象总和”或者”老年代可用空间”大于”历次Minor GC升入老年代对象的平均大小”,两个条件满足一个,就可以直接进行Y GC,不需要提前触发Full GC了。
  6. 是新生代Youth GC后的存活对象大于Survivor,那么就会进入老年代,此时老年代内存不足,触发Full GC。这里的不足就是判断条件后还是不足或者经过判断后进行YGC后放入老年代此时的空间不足,然后进行Full GC,就会出现频繁Full GC。达到一定情况后,就会OOM了。
  7. 是如果用的是CMS收集器,老年代可用内存大于历次新生代GC后进入老年代的对象平均大小,但是老年代已经使用的内存空间超过了(”-XX:CMSInitiatingOccupancyFaction=92%”JDK6默认值 )这个参数指定的比例,也会自动触发Full GC。

Mixed GC

G1中特有的,当老年代内存占据45%就会触发mixed GC,对新生代和老年代都进行回收。

JVM的垃圾回收器

image-20240531155915825

垃圾回收器主要分年轻代和老年代。

年轻代:Serial、PraNew、Parallel Scavenge

老年代:Serial Old、Parallel Old、CMS

回收整个Java堆的:G1收集器

JDK1.8 : G1

java11:G1

参考:

JVM垃圾回收详解(重点)