You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何手动触发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时的标记、清理工作量会大幅增加。以下是具体步骤和代码示例:

步骤说明:

  1. 调整JVM参数:缩小新生代(让对象快速晋升),放大老年代(容纳大量对象)。比如设置:

    -Xms4g -Xmx4g -Xmn512m -XX:+UseParallelOldGC
    

    堆总大小4G,新生代512M,老年代就有3.5G左右;选择ParallelOldGC收集器,它的Full GC是STW(停顿)式的,更容易拉长耗时。

  2. 分阶段填充老年代:

    • 先填满新生代,触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:32:26