Full GC

Full GC(Full Garbage Collection)是Java虚拟机执行的一种全局性、包括整个堆的垃圾回收操作。相对于新生代或老年代的局部性垃圾回收,Full GC的开销通常较大,因此应该尽量避免频繁触发。

1、full gc主要干了什么?

JVM Full GC(Full Garbage Collection)是一种垃圾回收的机制,用于回收整个堆内存中的所有未使用对象,包括年轻代和老年代中的对象。

在进行Full GC时,主要会做以下几件事情:

(1)停止所有的应用程序线程:为了避免在Full GC期间产生新的垃圾对象,JVM需要先暂停所有的应用程序线程。

(2)标记所有存活的对象:JVM会从根对象(如静态变量、局部变量等)开始遍历所有可达的对象,并标记所有存活的对象。这一过程类似于Young GC中的标记阶段。

(3)整理内存空间:在标记所有存活对象之后,JVM会将所有存活对象移动到堆内存的一端,并将所有未使用的内存空间整理到另一端,从而释放出一段连续的内存空间。这一过程类似于Young GC中的整理阶段。

(4)释放未使用的内存空间:在整理内存空间之后,JVM会将整个堆内存中未使用的内存空间全部释放掉,从而回收所有不再使用的对象。

(5)重置指针:在释放未使用的内存空间之后,JVM会将内存指针指向堆内存的起始位置,以便下一次垃圾回收使用。

 

需要注意的是,Full GC通常是一种非常耗时的操作,因为它需要遍历整个堆内存中的所有对象,并对内存空间进行整理和释放。因此,在实际开发中,我们需要尽可能地避免Full GC的发生,以提高应用程序的性能和响应速度。

2、full gc触发条件?

充分了解了jvm的内存结构之后,下面我们就来说说什么情况下会触发gc。触发full gc的情况主要有这几种:

  1. 老年代空间不足: 如果老年代无法容纳新创建的对象或者晋升过来的对象,将触发Full GC。这可能是由于老年代中有大对象存在,或者程序中创建了大量的长寿命对象。

  2. 永久代(在Java 8之前,Java 8之后是元空间)空间不足: 如果永久代(或者元空间)无法容纳新的类定义、常量等元数据,也可能触发Full GC。这种情况可能发生在动态生成大量类或者加载大量类文件的场景。

  3. CMS GC出现Concurrent Mode Failure: CMS(Concurrent Mark-Sweep)垃圾回收器在执行垃圾回收时,会有一个初始的标记阶段和一个并发的标记清除阶段。如果在CMS的并发标记阶段,新的垃圾对象产生速度过快,导致老年代的空间不足,CMS可能会放弃并发标记,转而使用Serial收集器执行Full GC。这个情况被称为Concurrent Mode Failure。

  4. System.gc(): 手动调用System.gc()或者Runtime.getRuntime().gc(),尽管这并不保证会立即触发Full GC,因为Java虚拟机可以选择是否响应这个请求。

 

3、JVM 垃圾回收之Minor GC、Major GC和Full GC之间的区别?

1、按照 回收区域 划分的GC 分类

JVM在进行GC时,并非每次对三个内存(新生代、老年代、方法区)区域一起回收,大部分时候回收的都是新生代。

针对Hotspot VM 的实现,它里面的GC按照回收区域分为两种大类:一种是部分收集(Partial GC),另一种是整堆收集(Full GC)

1、部分收集(Partial GC):只针对部分区域进行垃圾收集。其中又分为:
	1.1、新生代收集(Minor GC/Young GC):只针对新生代的垃圾收集。具体点的是Eden区满时触发GC。
										Survivor满不会触发Minor GC 。
	1.2、老年代收集(Major GC/Old GC):只针对 老年代的垃圾收集。
		目前,只有CMS收集器会有单独收集老年代的行为。
		注意,很多时候,Major GC 会和Full GC混淆使用,需要具体分辨是老年代的回收还是整堆回收。
	
	1.3、混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。
		目前只有G1收集器会有这种行为。
		
2、整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。	

2、Minor GC、Major GC、Full GC 的简单说明

2.1、Minor GC

当年轻代(Eden区)满时就会触发 Minor GC,这里的年轻代满指的是 Eden区满。Survivor 满不会触发 Minor GC 。

从年轻代空间(主要是 Eden区)回收内存被称为 Minor GC。

发生Minor GC事件需要注意:

  1. 当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。所以分配率越高,越频繁执行 Minor GC。

  2. 内存池被填满的时候,其中的内容全部会被复制,指针会从0开始跟踪空闲内存。Eden 和 Survivor 区进行了标记和复制操作,取代了经典的标记、扫描、压缩、清理操作。所以 Eden 和 Survivor 区不存在内存碎片。写指针总是停留在所使用内存池的顶部。

  3. 执行 Minor GC 操作时,不会影响到永久代。从永久代到年轻代的引用被当成 GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉。

  4. 对于大部分应用程序,Minor GC 操作时应用程序停顿导致的延迟都是可以忽略不计的。因为,大部分 Eden 区中的对象都能被认为是垃圾,永远也不会被复制到 Survivor 区或者老年代空间。如果正好相反,Eden 区大部分新生对象不符合 GC 条件,Minor GC 执行时暂停的时间将会长很多。

2.2、Major GC

CMS收集器中,当老年代满时会触发 Major GC。

目前,只有CMS收集器会有单独收集老年代的行为。其他收集器均无此行为。

针对新生代(主要指Eden区)的Minor GC 比较常见,各个收集器均支持。

通常能单独发生收集行为的只是新生代的Minor GC,所以这里“反过来”的情况只是理论上允许,实际上除了CMS收集器,其他都不存在只针对老年代的收集。(英文翻译过来的,要细品!)

2.3、Full GC

Full GC 对收集整堆(新生代、老年代)和方法区的垃圾收集。

当年老代满时会引发Full GC,Full GC将会同时回收新生代、年老代 ;
当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载 。

(1)调用System.gc时,系统建议执行Full GC,但是不一定会执行 。
(2)老年代空间不足
(3)方法区空间不足
(4)通过 Minor GC 后进入老年代的空间大于老年代的可用内存
(5)由Eden区、S0(或S1)区向 S1(或S0)区复制时,对象大小大于To Space可用内存,则把该对象直接转存到老年代,且老年代的可用内存小于该对象大小 。

3、总结

  • Minor GC 是 清理 新生代中的Eden区,Survivor区满时不会触发 ;
  • Major GC 是 清理 老年代 ;
  • Full GC 是 清理整个堆和方法区,包括 年轻代、老年代和方法区。
 

 

posted @ 2023-11-24 11:33  guoyu1  阅读(732)  评论(0编辑  收藏  举报