如何手动触发Java长时间Full GC及编写代码让老年代Full GC耗时超3-5秒
如何在Java中手动触发长时间Full GC?以及如何让对象进入老年代并拉长Full GC耗时?
一、手动触发Full GC的几种方式
先说明哈:Java里没有绝对能强制JVM执行Full GC的方法(JVM有自己的GC决策逻辑),但以下几种手段可以强烈引导JVM触发Full GC:
System.gc()方法
这是最常用的方式,本质是向JVM发送“建议执行GC”的信号。默认配置下,大多数JVM会响应这个信号触发Full GC,但不保证100%生效。如果想让它触发并发Full GC(比如CMS或G1的并发收集),可以配合JVM参数:-XX:+ExplicitGCInvokesConcurrent,或者-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses(同时触发无用类卸载)。通过JMX API触发
可以借助Java管理扩展直接调用GC相关的MBean,精准控制GC行为:import java.lang.management.ManagementFactory; import javax.management.MBeanServer; import javax.management.ObjectName; public class TriggerGC { public static void main(String[] args) throws Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName gcName = new ObjectName("java.lang:type=GarbageCollector,name=*"); for (ObjectName name : server.queryNames(gcName, null)) { // 两个布尔参数:是否执行Full GC、是否阻塞至GC完成 server.invoke(name, "collect", new Object[]{Boolean.TRUE, Boolean.TRUE}, new String[]{"boolean", "boolean"}); } } }使用JDK命令行工具
生产环境排查时常用jcmd,先通过jps找到Java进程ID,再执行:jcmd <pid> GC.run这个命令同样会触发Full GC,比
System.gc()更直接。
二、让对象进入老年代并拉长Full GC耗时到3-5秒以上
核心思路是让老年代塞满足够多、足够大的存活对象,这样GC时的标记、清理工作量会大幅增加。以下是具体步骤和代码示例:
步骤说明:
调整JVM参数:缩小新生代(让对象快速晋升),放大老年代(容纳大量对象)。比如设置:
-Xms4g -Xmx4g -Xmn512m -XX:+UseParallelOldGC堆总大小4G,新生代512M,老年代就有3.5G左右;选择ParallelOldGC收集器,它的Full GC是STW(停顿)式的,更容易拉长耗时。
分阶段填充老年代:
- 先填满新生代,触发Minor GC让对象晋升到老年代(要保留对象引用,避免被回收)。
- 再创建大量大对象,直接分配到老年代(大对象超过新生代分配阈值时会绕过新生代)。
代码示例:
import java.util.ArrayList; import java.util.List; public class LongFullGC { public static void main(String[] args) throws InterruptedException { // 1. 填充新生代,触发Minor GC让对象晋升到老年代 List<byte[]> youngGenFiller = new ArrayList<>(); // 填充500M数据,超过新生代512M阈值,触发Minor GC for (int i = 0; i < 500; i++) { youngGenFiller.add(new byte[1024 * 1024]); // 1M数组 } System.gc(); // 手动触发Minor GC,加速对象晋升 Thread.sleep(1000); // 等待GC完成 // 2. 往老年代填充大量大对象,占满大部分空间 List<byte[]> oldGenFiller = new ArrayList<>(); // 每个数组100M,创建30个就是3G,接近老年代3.5G的容量 for (int i = 0; i < 30; i++) { oldGenFiller.add(new byte[100 * 1024 * 1024]); Thread.sleep(500); // 分批创建,避免瞬间OOM } // 3. 触发Full GC并计时 System.out.println("Starting Full GC..."); long startTime = System.currentTimeMillis(); System.gc(); long endTime = System.currentTimeMillis(); System.out.println("Full GC completed in: " + (endTime - startTime) + " ms"); } }
注意事项:
- 需根据自己的机器配置调整对象大小和数量,如果耗时不够,就增加老年代的对象数量/大小。
- 确保老年代有足够空间,避免触发OOM。
- 尽量用ParallelOldGC或SerialGC这类收集器,G1/ZGC等低延迟收集器的Full GC策略优化过,很难达到3-5秒的耗时。
内容的提问来源于stack exchange,提问作者Gnayils
相关产品推荐
相关产品推荐

