死循环本身不会直接导致内存溢出,但持续创建对象且不释放引用会迅速耗尽堆内存并触发outofmemoryerror;空转仅占用cpu,而循环内new对象+强引用将使gc无法回收,几秒至几十秒内即可oom。

死循环本身不会直接导致内存溢出,但一旦它持续分配新对象且不释放引用,就会迅速耗尽堆内存,最终触发 OutOfMemoryError: Java heap space。
死循环+对象创建=堆内存快速见底
Java 的内存溢出(OOM)本质是堆空间被占满、GC 无法回收足够内存。死循环若只是空转(比如 while(true) {}),只会吃 CPU,不占堆内存;但只要循环体内反复 new 对象,问题就来了。
- 每次
new Object()或new byte[1024*1024]都会向堆申请内存 - 如果这些对象被集合、静态变量或长生命周期对象持续引用,GC 就无法回收
- 堆空间以 MB/秒级速度被填满,几秒到几十秒内就会 OOM
典型高危写法:集合无节制扩容
下面这段代码在生产环境极易引发事故:
List<string> data = new ArrayList();
while (true) {
data.add("item-" + System.nanoTime()); // 每次都 new 字符串
}</string>
它的问题在于:
- ArrayList 底层数组会自动扩容,每次扩容都要复制旧数组 → 额外内存开销
- 字符串对象不断新增,且全部保留在 list 中 → 引用链牢固,GC 不会清理
- 即使单个字符串很小,百万级累积后仍可轻松突破 512MB 堆限制
缓存场景下的隐性死循环风险
有些“非显式死循环”更危险——表面看有退出条件,但逻辑缺陷导致实际无限执行。例如:
- 分页查询未校验
pageNo是否越界,结果翻到第 10000 页还在查 - 消息重试机制未设最大次数,失败消息反复入队、反复处理、反复 new 对象
- 缓存预热时遍历用户表,每个用户生成 6 个前缀索引(如 “a”、“aa”、“ab”…),1 万用户 → 6 万个对象 → 内存翻 6 倍
怎么避免这类灾难
关键不是“能不能写死循环”,而是“循环里有没有失控的内存增长”。实用建议:
- 所有循环创建对象的场景,必须加数量阈值或时间截止(如
for (int i = 0; i ) - 用集合暂存对象时,明确生命周期:用完立刻
clear()或重新初始化局部变量 - 缓存类结构优先用
LinkedHashMap实现 LRU,或引入 Guava Cache / Caffeine,自带容量控制和过期策略 - 本地测试时加 JVM 参数
-XX:+PrintGCDetails -Xloggc:gc.log,观察 GC 频率与堆使用趋势
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











