使用ArrayList::new时触发意外OOM错误,原因何在?
分析OutOfMemoryError的原因
哇,这个问题有点反直觉啊——按道理说你代码里创建的所有对象加起来占用的内存才几MB,16GB内存的机器完全不可能触发OOM。让我仔细拆解一下可能的问题点:
先算一笔内存账(以64位JVM开启指针压缩为例)
- 50000个
ListObject:每个对象包含2个int字段+对象头,总占用约24字节/个,总计≈1.2MB - HashMap中的50000个entry:每个
HashMap.Node包含hash值、key引用、value引用、next引用,总占用约32字节/个,总计≈1.6MB - 50000个空
ArrayList:每个空ArrayList包含对象头、数组引用、size字段,总占用约24字节/个,总计≈1.2MB - 自动装箱生成的
Integer对象:因为你的key范围是0-99999,超过了Integer缓存池(-128~127),每个key都会生成新Integer,每个约16字节,总计≈800KB
所有对象加起来才不到5MB,完全不可能让16GB内存的机器OOM。那问题肯定出在其他地方:
可能的原因
- JVM堆内存设置过小:默认情况下JVM不会把全部物理内存分配给堆,比如64位JDK默认堆最大值是物理内存的1/4(也就是4GB),但如果你的环境被修改过默认参数,或者手动设置了很小的
-Xmx值(比如-Xmx128M),就可能触发OOM。 - 机器内存被其他进程抢占:如果你的机器上同时运行了其他占用大量内存的程序(比如大型数据库、虚拟机),导致剩余可用内存不足以让JVM分配堆空间,也会出现OOM。
- 代码存在笔误或实际实现不符:
- 你写的
count是50000,但实际运行的代码里可能是更大的数值(比如500万或5000万); - 你提供的
ListObject是用int存key/value,但实际代码里可能是大对象(比如长字符串、大数组),导致每个ListObject占用大量内存。
- 你写的
- 罕见的JDK版本bug:某些非常旧的JDK版本中,
HashMap或computeIfAbsent的实现可能存在内存泄漏,但这种情况概率极低,JDK 8及以后的版本已经修复了大部分这类问题。
解决建议
- 手动设置JVM堆内存参数:启动程序时添加
-Xmx8G(或更大的值,比如-Xmx12G),强制分配足够的堆内存。 - 检查机器内存使用情况:打开任务管理器(Windows)或
top命令(Linux),看看是否有其他进程占用了大量内存,关闭不必要的进程释放资源。 - 核对代码一致性:确认运行的代码和你提供的完全一致,特别是
count的值和ListObject的字段类型。 - 用内存分析工具定位问题:使用VisualVM、MAT等工具dump堆内存快照,查看到底是哪些对象占用了大量内存,这是最直接的排查方法。
内容的提问来源于stack exchange,提问作者Joker
相关产品推荐
相关产品推荐

