java堆外内存泄露定位
¶现象
- 服务器运行一段时间后,内存占用越来越高,最终导致服务器OOM。
- 通过查看相关的快照和监控,发现堆内存使用正常,但是机器的RSS一直在增长。
¶预排查
- 是否创建了大对象
- 是否使用了堆外内存,且未及时释放内存
- 是使用了jni方法,且未及时释放内存
- 是否使用了相关资源, 比如stream, file, socket等,且未及时释放资源
¶定位
- 首先使用jmap把内存快照dump下来
如果是堆内内存泄露的话, 通过快照分析基本就能定位到问题,但是堆外内存泄露的话,就需要通过其他方式定位了
- 同时通过确认线程状态和数量,确认也不是线程数量导致的内存泄露
- 因此需要排查是否是堆外内存泄露导致的
¶0. 开启NMT
由于是线上环境,暂不考虑开启NMT,因此需要通过其他方式定位
¶1. 使用jmap命令
发现MaxMetaspaceSize未设置最大值,那么是否可能是元空间内存泄露导致的呢?
¶2. 观察类加载和卸载情况
在本地环境,添加启动参数-verbose:class
,观察类加载和卸载情况
再本地环境跑一段时间,然后手动出发gc, 通过 jmap
命令或者 System.gc()
发现类加载也正常, 没有什么特别的情况
¶3. 使用strace和pmap命令
参考https://ww.dandelioncloud.cn/article/details/1599739989472788481
1 | pmap -x PID |
¶3. 使用gperftools
¶linux
1 | # 使用 yum 安装 |
¶mac
1 | # 使用 Brew 安装 |