内存泄露
基本概念参考:https://www.cnblogs.com/0201zcr/p/4805920.html
内存泄露 vs 内存溢出
- 内存溢出(OOM):程序申请内存时,没有足够的空间供其使用
- 内存泄露:程序申请内存成功,使用完后,这部分空间无法被GC回收,导致可用内存减少,一次内存泄露危害可以忽略,但内存泄露堆积会导致内存溢出
内存泄露本质
垃圾回收机制需要通过可达性分析标记垃圾对象,没有被标记的对象不会被回收,内存泄漏是使用完后之后不再被使用的对象由于依然被引用(一般是强引用),导致GC未将其标记为垃圾导致没有被回收。
- 强引用:无论内存是否充足,都不会被回收的对象引用
- 软引用:在内存空间不足时会被回收,内存充足的情况下不会被回收
- 弱引用:在垃圾回收时,只要发现弱引用,直接被回收
- 虚引用:跟踪对象的回收,清理被销毁对象的相关资源,无法通过get获取对象,直接返回null
这里简单介绍下四种引用类型的应用场景:
- 强引用:几乎所有常规对象都使用强引用,确保对象在程序运行期间始终存在
- 软引用:内存敏感的缓存,这里的缓存是指由JVM管理的内存,redis这种独立于JVM存在的缓存不在考虑范围内
- 弱引用:临时缓存,只要数据不被强引用持有了,GC立即回收(ThreadLocal)
- 虚引用:跟踪对象被回收后执行某些清理操作,不能通过虚引用访问某个对象
内存泄露现象
发生内存泄露时,存在一些异常现象,如下:
- 内存占用率持续缓慢上升,而非正常的锯齿状
- GC频率和耗时持续增长,CPU利用率飙升
- 各类性能指标异常:吞吐率、接口响应时间、系统负载等
内存泄露排查思路
- 观察指标,如果内存持续增长,且GC效益很低,基本可以确定是内存泄漏;
- 内存缓慢增长:内存泄漏
- 内存瞬间溢出:内存溢出
- top查看进程各项指标,重点关注CPU利用率(随着内存持续泄露,一般垃圾回收线程利用率会飙到异常高)
- 进一步分析GC日志,如果GC频率很高,基本可以确定发生内存泄露
- 通过内存快照分析工具分析内存快照,查看内存空间具体的使用情况,定位内存空间占用率异常高的类,追溯代码逻辑
发生内存泄露时,重启可以暂时解决问题,线上发生内存泄漏,转储内存快照并重启机器,之后分析内存快照,尝试在测试环境复现,追溯泄露源头
常见内存泄露场景
- 静态集合类
1 | |
- ThreadLocal:ThreadLocal的key为弱引用,value为强引用
- 资源未关闭
1 | |
内存泄露
http://xuxiusheng.github.io/2025/12/30/内存泄露/