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

Java程序抛出OutOfMemoryError但堆转储显示大量空闲内存原因排查

问题分析与解决方案

你遇到的这个问题,根源大概率是G1垃圾收集器的Remembered Set(RS,记忆集合)内部结构——那些你看到的int[262136]数组,正是G1用来跟踪跨Region引用的核心数据结构,并非你的代码直接创建的。

为什么会出现这种情况?

Java 11和14默认使用G1收集器,它将堆划分为多个大小相等的Region。为了高效处理垃圾回收,每个Region都对应一个Remembered Set,用来记录其他Region对当前Region内对象的引用。这些RS的底层实现就是固定大小的int数组(你看到的262136长度,换算下来刚好是~1MB左右,和G1默认的Region大小(通常2MB)匹配)。

当你的堆接近-Xmx设置的8GB上限时,G1需要维护的RS数量会随着Region数量增加而剧增(8GB堆用2MB Region的话,就是4096个Region),所有RS的总内存占用刚好能达到4GB左右——这正好对应你堆转储中那部分“未引用”的内存。

至于为什么工具会把这些数组标记为“未引用对象”,是因为这些数组属于JVM内部的私有实现,MAT或VisualVM无法识别它们被G1收集器的核心对象持有引用,所以误判为可回收的垃圾,但实际上它们是存活的、不可回收的内部结构,正是它们占用的4GB内存加上你的应用数据的4GB,直接填满了8GB堆,引发了OutOfMemoryError。

解决方案

针对这个问题,你可以尝试以下几种方案:

  • 调整G1的Region大小:通过-XX:G1HeapRegionSize参数增大Region的尺寸(比如设为4MB或8MB),这样Region的数量会减少,RS的总内存占用也会随之降低。例如:
    java -Xmx8000m -XX:G1HeapRegionSize=4m YourMainClass
    
  • 切换到其他垃圾收集器:如果你的应用场景适合,可以改用Parallel GC(吞吐量优先),它没有G1这种RS结构,也就不会产生这些占用内存的int数组。启动参数添加:
    java -Xmx8000m -XX:+UseParallelGC YourMainClass
    
  • 增大堆内存上限:如果资源允许,直接调高-Xmx的值(比如-Xmx12000m),给G1的RS和你的应用数据都留出足够的空间。

内容的提问来源于stack exchange,提问作者fjalvingh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:01:26