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的情况主要有这几种:
-
老年代空间不足: 如果老年代无法容纳新创建的对象或者晋升过来的对象,将触发Full GC。这可能是由于老年代中有大对象存在,或者程序中创建了大量的长寿命对象。
-
永久代(在Java 8之前,Java 8之后是元空间)空间不足: 如果永久代(或者元空间)无法容纳新的类定义、常量等元数据,也可能触发Full GC。这种情况可能发生在动态生成大量类或者加载大量类文件的场景。
-
CMS GC出现Concurrent Mode Failure: CMS(Concurrent Mark-Sweep)垃圾回收器在执行垃圾回收时,会有一个初始的标记阶段和一个并发的标记清除阶段。如果在CMS的并发标记阶段,新的垃圾对象产生速度过快,导致老年代的空间不足,CMS可能会放弃并发标记,转而使用Serial收集器执行Full GC。这个情况被称为Concurrent Mode Failure。
-
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事件需要注意:
-
当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。所以分配率越高,越频繁执行 Minor GC。
-
内存池被填满的时候,其中的内容全部会被复制,指针会从0开始跟踪空闲内存。Eden 和 Survivor 区进行了标记和复制操作,取代了经典的标记、扫描、压缩、清理操作。所以 Eden 和 Survivor 区不存在内存碎片。写指针总是停留在所使用内存池的顶部。
-
执行 Minor GC 操作时,不会影响到永久代。从永久代到年轻代的引用被当成 GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉。
-
对于大部分应用程序,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 是 清理整个堆和方法区,包括 年轻代、老年代和方法区。