System.gc()不能模拟高内存,它仅是回收建议;真正模拟需持续分配并强引用大量对象,如存入static容器、禁用显式GC,并通过MemoryMXBean和GC日志验证堆占用真实上升。

System.gc() 不能用来“模拟高内存”,它既不制造内存压力,也不提升内存占用——它只是向 JVM 提出一次回收建议。想在手动压力测试中模拟高内存状态,关键在于主动分配并持有大量对象,让堆快速填满,而非靠调用 gc 来“制造压力”。
真正模拟高内存的核心:持续分配+阻止回收
高内存状态源于对象被创建后仍被强引用持有,JVM 无法回收。System.gc() 在这里不仅无效,反而可能干扰观测:
- 分配大数组或集合(如
new byte[100 * 1024 * 1024])并存入静态 List 或缓存 Map 中,切断其被回收的路径 - 避免局部变量自动释放:把对象赋值给 static 字段、单例容器或未清理的 ThreadLocal,延长生命周期
- 禁用显式 GC 干扰:确保 JVM 启动参数含
-XX:+DisableExplicitGC,防止 System.gc() 意外触发回收,掩盖真实内存堆积效果
配合监控确认高内存是否达成
仅看代码分配不够,要验证实际堆占用是否升高:
- 用
ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()在分配前后读取数值,确认增长明显(例如从 200MB → 1.8GB) - 开启 GC 日志:
-Xlog:gc*:file=gc.log,观察是否出现Allocation Failure触发的 Young GC 或老年代晋升 - 用 VisualVM 连接进程,实时查看 “Old Gen” 使用量曲线是否持续爬升,这才是高内存压力的可靠信号
为什么不该在循环里穿插 System.gc()
在压力循环中反复调用 System.gc() 不是模拟高内存,而是破坏测试真实性:
立即学习“Java免费学习笔记(深入)”;
- 它可能引发额外 Full GC,拉长单轮耗时,把“内存压力响应时间”扭曲成“GC 停顿时间”
- G1/ZGC 下大概率被忽略,但线程仍在等待,造成虚假的阻塞假象
- 日志中若出现
Full GC (System),说明你人为引入了 STW,测的已不是业务逻辑本身
更干净的高内存构造方式
比起依赖 System.gc(),直接控制对象生命周期更可控、可复现:
- 使用
ByteBuffer.allocateDirect()分配堆外内存,配合未 clean 的 Cleaner,使 Direct Memory 持续上涨(sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPool().getMemoryUsed()可查) - 构建长引用链:例如 A → B → C → 大 byte[],再只保留 A 的引用,让整条链无法被回收
- 模拟缓存泄漏:往 static ConcurrentHashMap 里 put 大量 key-value,且 value 包含图像、JSON 解析结果等重对象,不 remove


















