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 安装 |