当前位置: 首页 > 工具软件 > java-dirty > 使用案例 >

java项目内存泄露排查

南门洋
2023-12-01

问题:线上项目随着时间占用系统内存越来越大(甚至高的时候top命令查看mem占用量比程序设置的最大内存还要大)

  1. 考虑程序逻辑导致的内存泄露
    jmap -histo:live $pid
    查看前后程序的各个对象数量和大小,发现没有明显增加
    使用jmap -heap $pid
    查看前后使用量,也没有发现明显增加
    所以考虑其他原因造成的进程内存占用量在增加
    2.考虑堆外内存造成内存泄露
    #使用linux pmap命令查看进程的地址空间和占用的内存
    pmap -x $pid | sort -k3 -n
    Address Kbytes RSS Dirty Mode Mapping
    00007f59b1208000 24704 24068 24068 rwx-- [ anon ]
    00007f59aecff000 24704 24136 24136 rw— [ anon ]
    00007f59abcff000 24576 24576 24576 rw— [ anon ]
    00007f59923bf000 197760 196744 196744 rw— [ anon ]
    00007f599e4df000 221312 199756 199756 rw— [ anon ]
    0000000001bab000 617180 571056 571056 rw— [ anon ]
    00000004c0000000 12591384 3159804 3159804 rw— [ anon ]

less /proc/$pid/smaps

通过上诉两个命令查找到比较可疑的内存地址
注意:dump内存会挂起应用进程,一定要确保没有流量流入再使用

使用gdb命令dump出内存
#先连接程序
gdb -pid $pid
#进入gdb调试模式dump内存
dump memory mem.bin 7f43dc000000 7f440e000000
#mem.bin是内存dump出来的文件,后面是地址
strings mem.bin > mem.log #将二进制文件读取成字符串并输出到文件,方便查阅
less mem.log
查看可能的代码位置,通过位置查看逻辑哪里有泄露。
我们项目没发现什么问题

3.通过对比pmap -x $pid | sort -k3 -n前后文件,发现内存量增加主要集中在RSS Dirty这两项位置。

vm.dirty_background_ratio 是内存可以填充脏数据的百分比。这些脏数据稍后会写入磁盘,pdflush/flush/kdmflush这些后台进程会稍后清理脏数据。比如,我有32G内存,那么有3.2G的脏数据可以待着内存里,超过3.2G的话就会有后台进程来清理。
vm.dirty_ratio是可以用脏数据填充的绝对最大系统内存量,当系统到达此点时,必须将所有脏数据提交到磁盘,同时所有新的I/O块都会被阻塞,直到脏数据被写入磁盘。这通常是长I/O卡顿的原因,但这也是保证内存中不会存在过量脏数据的保护机制。
vm.dirty_background_bytes和vm.dirty_bytes是另一种指定这些参数的方法。如果设置_bytes版本,则_ratio版本将变为0,反之亦然。
vm.dirty_expire_centisecs 指定脏数据能存活的时间。在这里它的值是30秒。当 pdflush/flush/kdmflush 在运行的时候,他们会检查是否有数据超过这个时限,如果有则会把它异步地写到磁盘中。毕竟数据在内存里待太久也会有丢失风险。
vm.dirty_writeback_centisecs 指定多长时间 pdflush/flush/kdmflush 这些进程会唤醒一次,然后检查是否有缓存需要清理。

通过这里分析内存增加在rss和dirty,就应该和程序没多大关系,应该是某些io操作导致的,在本机写入磁盘的只有日志文件,所以考虑是日志输出量大导致的,将日志全部注释掉测试,内存没有增加,问题定位到了,下面就是怎么解决日志输出量大的问题了。
堆外内存排查参考
rss和dirty参考

 类似资料: