在Java虚拟机(JVM)中,垃圾收集(Garbage Collection,简称GC)是管理内存的关键机制。Full GC(也称为Major GC或老年代GC)是一种较为耗时的垃圾收集过程,会对整个堆(包括年轻代和老年代)进行垃圾收集。
注:
部分收集(Partial GC):指目标不是完整收集整个 Java 堆的垃圾收集,其中又分为:
- 新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。
- 老年代收集(Major GC/0ld GC):指目标只是老年代的垃圾收集。目前只有CMS 收集器会有单独收集老年代的行为。
- 混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有 G1收集器会有这种行为。
整堆收集(Full GC):收集整个 Java 堆和方法区的垃圾收集。
触发Full GC的条件如下:
当老年代(Old Generation)的内存使用达到阈值时,JVM会触发Full GC以释放老年代中的不再使用的对象。
对于使用旧的HotSpot JVM的Java应用程序,永久代(Permanent Generation)中的内存使用接近或达到上限时,会触发Full GC以回收永久代中的类元数据和静态变量。需要注意的是,JDK 8后永久代被移除了,取而代之的是元空间(Metaspace)。
显式调用System.gc()
请求进行垃圾收集时,JVM可能会触发Full GC。尽管JVM并不保证每次都进行Full GC,但在某些情况下会触发。
在某些情况下,例如生成堆转储(Heap Dump)以进行内存分析时,JVM会触发Full GC以确保获取准确的堆内存快照。
在使用Concurrent Mark-Sweep(CMS)垃圾收集器时,如果年轻代的对象在转移到老年代时,老年代没有足够的空间来容纳这些对象,会发生Promotion Failure,这会触发Full GC。
对于G1垃圾收集器(G1 GC),如果在Mixed GC过程中,无法成功回收足够的空间,也可能会触发Full GC。
当JVM尝试分配对象时,如果堆内存中没有足够的空间来容纳新的对象,可能会触发Full GC以回收内存并尝试重新分配。
在JDK 8及以后版本,Metaspace替代了永久代。如果Metaspace满,也会触发Full GC以尝试回收类元数据和静态变量。
以下是一些可能触发Full GC的Java代码示例:
public class FullGCExample {
public static void main(String[] args) {
// 示例1: 手动调用System.gc()
System.gc();
// 示例2: 分配大量对象导致内存分配失败
List<byte[]> list = new ArrayList<>();
try {
for (int i = 0; i < 1000; i++) {
list.add(new byte[1024 * 1024]); // 分配1MB对象
}
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
// 示例3: 生成Heap Dump
try {
// 通过JVM选项触发Heap Dump,例如:-XX:+HeapDumpOnOutOfMemoryError
// 或通过JVM工具,如jmap -dump:live,format=b,file=heapdump.hprof
} catch (Exception e) {
e.printStackTrace();
}
}
}
触发Full GC的条件主要包括老年代内存满、显式调用System.gc()
、生成Heap Dump、CMS GC的Promotion Failure、G1 GC的Mixed GC失败、内存分配失败和Metaspace满等情况。了解这些条件有助于优化JVM性能,避免频繁触发Full GC对应用性能造成的影响。