内存泄漏和内存溢出的区别是什么
2026/3/30大约 4 分钟约 1078 字
内存泄漏和内存溢出经常一起被问,但它们不是一回事。
最核心的一句话是:
内存泄漏是“该回收的没回收”,内存溢出是“想申请的申请不到”。
一、什么是内存泄漏
内存泄漏是指:
程序已经不再需要某块内存了,但这块内存没有被正确释放或回收,导致它一直被占用。
它的特点通常是:
- 不一定立刻报错
- 会随着时间一点点积累
- 让可用内存越来越少
- 最终可能把程序拖垮
所以内存泄漏更像是一种慢性问题。
二、什么是内存溢出
内存溢出通常是指:
程序在申请内存时,系统已经无法再提供足够空间,导致分配失败。
常见表现包括:
malloc返回失败- 堆内存不足导致 OOM
- 栈空间不足导致栈溢出
- 进程被系统直接杀掉
所以内存溢出更像是一种直接暴露出来的错误结果。
三、两者的最本质区别
内存泄漏
- 本该回收的内存没有回收
- 问题在于“该释放没释放”
内存溢出
- 申请新内存时失败
- 问题在于“已经没有足够空间了”
因此两者的关系通常是:
内存泄漏长期积累,可能最终导致内存溢出。
但反过来,内存溢出不一定都是泄漏引起的,也可能只是一次性申请太大,或者配置本来就太小。
四、内存泄漏的典型场景
1. C/C++ 中申请后忘记释放
最经典的情况就是:
malloc后忘记freenew后忘记delete
2. 指针管理不当
例如丢失了指向某块堆内存的唯一指针,导致这块内存既没法继续用,也没法释放。
3. Java 等 GC 语言中的逻辑泄漏
Java 虽然没有手动 free,但依然会有泄漏。
关键不是“互相引用”,而是:
- 对象已经没有业务意义
- 但仍然被长生命周期对象错误持有
- 从 GC Roots 看依然可达
- 因而无法回收
典型场景包括:
- 静态集合一直保存对象
- 缓存无限增长
- 监听器没有移除
ThreadLocal没清理
五、内存溢出的典型场景
1. 堆溢出
比如:
- 不断创建对象
- 泄漏积累过久
- 一次性申请超大数组
- JVM 堆配置过小
2. 栈溢出
比如:
- 无限递归
- 递归层级过深
- 局部变量太大
3. 直接申请超大内存失败
例如程序一下申请远超系统可用空间的一大块内存,也会导致分配失败。
六、为什么说内存泄漏不一定立刻报错,但很危险
因为泄漏往往不是一次性爆炸,而是:
- 一点点漏
- 一直积累
- 运行越久越明显
常见线上表现是:
- 程序越来越吃内存
- 运行时间越长越慢
- 重启后短时间恢复正常
- 跑久了又再次出现问题
所以它虽然不一定马上崩,但非常危险。
七、为什么说内存溢出更像“结果”
因为内存溢出描述的是:
当前这次申请已经失败了。
它是一种现象,而背后的根因可能很多:
- 内存泄漏
- 正常业务流量太大
- 配置过小
- 一次性申请过多
- 无限递归
所以面试里说“内存溢出是结果,根因要继续分析”会比较稳。
八、总结
内存泄漏是指程序已经不再需要某块内存了,但这块内存没有被正确释放或回收,导致它一直被占用;内存溢出是指程序申请内存时,系统已经无法再提供足够空间,导致分配失败。两者的关系是,内存泄漏长期积累后可能导致内存溢出,但内存溢出不一定都是泄漏造成的,也可能是配置过小、申请过大或递归过深等原因引起的。
