java 中的 full gc 通常由老年代空间不足、系统元数据区(metaspace)溢出或显式调用触发。具体做法包括:当对象分配无法在老年代找到连续内存时,jvm 会尝试触发 full gc;当 metaspace 达到上限时也会触发;此外,通过命令行参数 -xx:+disableexplicitgc 可以控制是否允许代码中显式请求 full gc。

老年代空间不足如何触发 Full GC
当 JVM 尝试在老年代分配对象时,如果剩余空间不足以容纳该对象,且经过 Minor GC 后依然无法获得足够空间,JVM 就会触发 Full GC。这是最常见的触发场景,旨在清理老年代中不再被引用的对象,以回收内存。

import java.util.ArrayList;
import java.util.List;
public class FullGCTest {
public static void main(String[] args) {
// 模拟老年代空间不足
List<byte> list = new ArrayList();
try {
while (true) {
// 每个元素约 1MB,直接存入老年代(假设新生代太小或对象较大)
list.add(new byte[1024 * 1024]);
}
} catch (OutOfMemoryError e) {
System.out.println("Full GC 尝试后仍失败: " + e.getMessage());
}
}
}</byte>
预期结果:程序抛出 OutOfMemoryError,并在控制台输出 Full GC 的日志信息(需开启 GC 日志),表明 Full GC 已执行但未能回收足够空间。
Metaspace 溢出如何触发 Full GC
从 Java 8 开始,永久代(PermGen)被移除,取而代之的是 Metaspace。当加载的类元数据超过 -XX:MaxMetaspaceSize 设置的上限时,JVM 会触发 Full GC 来卸载无用的类。如果 Full GC 后仍然无法释放足够的空间,则会抛出 OutOfMemoryError: Metaspace。
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型

import java.lang.reflect.Method;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.FixedValue;
public class MetaspaceTest {
public static void main(String[] args) throws Exception {
ByteBuddy byteBuddy = new ByteBuddy();
int count = 0;
while (true) {
// 动态生成大量类,占用 Metaspace
DynamicType.Unloaded> type = byteBuddy
.subclass(Object.class)
.name("com.example.GeneratedClass" + count++)
.make();
// 注意:实际测试中需要确保这些类不被引用,否则不会被卸载
// 这里为了演示溢出,我们不断加载新类
type.load(MetaspaceTest.class.getClassLoader());
}
}
}
预期结果:程序抛出 OutOfMemoryError: Metaspace,并伴随 Full GC 日志,表明 Metaspace 已满且 Full GC 未能回收足够空间。
显式调用 System.gc() 的行为
开发者可以通过调用 System.gc() 显式请求 JVM 进行垃圾回收。默认情况下,这会触发 Full GC。但是,如果 JVM 启动时设置了 -XX:+DisableExplicitGC 参数,则 System.gc() 调用将被忽略,不会触发任何 GC。这种行为常用于避免在生产环境中因意外调用而引发不必要的停顿。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










