Java 使用pmap和gdb查找本机内存泄漏
我正在调试java应用程序中的本机内存泄漏。rss每天增长1GB,而堆没有增长。在比较pmap随时间的输出时,我看到在堆的顶部或两个本机库之间添加了多个anon块Java 使用pmap和gdb查找本机内存泄漏,java,memory-management,memory-leaks,gdb,memory-leak-detector,Java,Memory Management,Memory Leaks,Gdb,Memory Leak Detector,我正在调试java应用程序中的本机内存泄漏。rss每天增长1GB,而堆没有增长。在比较pmap随时间的输出时,我看到在堆的顶部或两个本机库之间添加了多个anon块 Address Kbytes RSS Dirty Mode Mapping 0000000000400000 4 4 0 r-x-- java 0000000000601000 4 4 4 rw--- java 00000000
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 4 4 0 r-x-- java
0000000000601000 4 4 4 rw--- java
00000000008fc000 64156 64028 64028 rw--- [ anon ]
00000006c0000000 2467840 2466824 2466824 rw--- [ anon ] (heap)
0000000756a00000 2775040 0 0 ----- [ anon ]
0000000800000000 39808 39636 39636 rw--- [ anon ]
00000008026e0000 607360 0 0 ----- [ anon ]
00007fc8f0000000 11268 10944 10944 rw--- [ anon ]
00007fc8f0b01000 54268 0 0 ----- [ anon ]
00007fc938000000 49204 46164 46164 rw--- [ anon ]
00007fc93b00d000 16332 0 0 ----- [ anon ]
00007fc940000000 126784 126784 126784 rw--- [ anon ]
00007fc947bd0000 4288 0 0 ----- [ anon ]
00007fc948000000 65512 65512 65512 rw--- [ anon ]
.....a lot of new anon blocks with memory 1012 and also ~64MB block shown in screenshot
00007fc98c448000 16 12 0 r-x-- sssd_pac_plugin.so
.....anon blocks with memormy increased over time:
00007fca747fe000 2044 0 0 ----- librmi.so
.....anon blocks with memormy increased over time:
00007fcb58015000 44 32 0 r-x-- libkrb5support.so.0.1
.............................................other libraries
00007fcbad8f8000 4 4 4 rw--- libnio.so
.....anon blocks with memormy increased over time like :
00007fcbb0000000 65420 65404 65404 rw--- [ anon ]
00007fcbc4f7e000 4820 4820 4820 rw--- [ anon ]
00007fcbc5433000 5420 0 0 ----- [ anon ]
00007fcbc597e000 90112 88172 88172 rwx-- [ anon ]
.....anon blocks with memormy increased over time
00007fcbd96ea000 44 16 0 r-x-- libjimage.so
...............................................other libraries
00007fcbdcdd9000 4 4 4 r---- ld-2.17.so
00007fcbdcdda000 4 4 4 rw--- ld-2.17.so
00007fcbdcddb000 4 4 4 rw--- [ anon ]
00007ffdbd52c000 140 40 40 rw--- [ stack ]
00007ffdbd578000 8 8 0 r-x-- [ anon ]
ffffffffff600000 4 0 0 r-x-- [ anon ]
---------------- ------- ------- -------
total kB 16585920 9216360 9206356
gdb-pid
转储内存mem.bin 0x00007fc940000000 0x00007fc940000000+126784
#将文件读取为:
字符串mem.bin
另一个观察结果是,许多新的块和旧的块增加到大约60-65MB。随着时间的推移,这些块的数量会增加很多。对rss增长的贡献最大。
我也尝试了libtcmalloc和profilers,主要问题是在生产环境中无法使用它们。在dev实例中,泄漏没有那么严重,因此无法验证探查器的输出。一种非常基本的方法:您可以尝试查看谁在调用
mmap
(而不是munmap
)
- 附加到进程中
- 在
上设置断点,使用命令打印参数和回溯(可能5帧)并继续mmap
- 对于
munmap
- 重定向输出
- 让它运行一天
- 分离
- 将
s与输出中的mmap
s匹配munmap
pmap
在侧面定期运行,您可以将较新的anon区域与mmap
回溯匹配(可能需要使用帧计数)
已经有这篇很好的小文章让你开始了 注:
- 您正在寻找
和mmap
,而不是munmap
和malloc
free
- 您必须从
mmap
- 我还没有尝试过文章中的脚本,但我认为它会像文章所说的那样
mmap
返回指令偏移量(从mmap
开始):
只需在同一主机上使用任何可执行文件启动gdb
[ aquila ~ ] $ gdb -q /usr/bin/ls
Reading symbols from /usr/bin/ls...Reading symbols from /usr/bin/ls...(no debugging symbols found)...done
.
(no debugging symbols found)...done.
Missing separate debuginfos, use: dnf debuginfo-install coreutils-8.27-5.fc26.x86_64
(gdb) set pagination off
(gdb) set breakpoint pending on
(gdb) b mmap
Function "mmap" not defined.
Breakpoint 1 (mmap) pending.
(gdb) r
Starting program: /usr/bin/ls
Breakpoint 1, 0x00007ffff7df2940 in mmap64 () from /lib64/ld-linux-x86-64.so.2
(gdb) disassemble
Dump of assembler code for function mmap64:
=> 0x00007ffff7df2940 <+0>: test %rdi,%rdi
0x00007ffff7df2943 <+3>: push %r15
0x00007ffff7df2945 <+5>: mov %r9,%r15
:
:
0x00007ffff7df2973 <+51>: mov $0x9,%eax
:
0x00007ffff7df2982 <+66>: pop %rbx
:
0x00007ffff7df298a <+74>: pop %r15
0x00007ffff7df298c <+76>: retq
0x00007ffff7df298d <+77>: nopl (%rax)
:
:
0x00007ffff7df29d8 <+152>: mov $0xffffffffffffffff,%rax
0x00007ffff7df29df <+159>: jmp 0x7ffff7df2982 <mmap64+66>
End of assembler dump.
[aquila~]$gdb-q/usr/bin/ls
正在从/usr/bin/ls读取符号…正在从/usr/bin/ls读取符号…(未找到调试符号)
.
(未找到调试符号)…完成。
缺少单独的调试信息,请使用:dnf debuginfo安装coreutils-8.27-5.fc26.x86_64
(gdb)设置分页关闭
(gdb)在上设置挂起的断点
(gdb)b mmap
未定义函数“mmap”。
断点1(mmap)挂起。
(gdb)r
启动程序:/usr/bin/ls
/lib64/ld-linux-x86-64.so.2中的mmap64()中的断点1,0x00007ffff7df2940
(gdb)拆卸
函数mmap64的汇编程序代码转储:
=>0x00007FF7DF2940:测试%rdi,%rdi
0x00007FF7DF2943:推送%r15
0x00007ffff7df2945:mov%r9,%r15
:
:
0x00007ffff7df2973:mov$0x9,%eax
:
0x00007FF7DF2982:弹出%rbx
:
0x00007FF7DF298A:弹出%r15
0x00007FF7DF298C:retq
0x00007FF7DF298D:nopl(%rax)
:
:
0x00007ffff7df29d8:mov$0xffffffffffffffff,%rax
0x00007FF7DF29DF:jmp 0x7FF7DF2982
汇编程序转储结束。
请注意此处的返回说明:
0x00007ffff7df298c <+76>: retq
0x00007ffff7df298c:retq
因此,在我的机器上,第二个断点必须设置为(mmap+76)
确定此偏移后,可以通过附加到目标进程并分解该偏移处的内容来验证此偏移。例如,将我当前的shell作为我的目标进程:
[ aquila ~ ] $ echo $$
9769
[ aquila ~ ] $ gdb -q
(gdb) attach 9769
Attaching to process 9769
Reading symbols from /usr/bin/bash...Reading symbols from /usr/bin/bash...(no debugging symbols found)..
.done.
(no debugging symbols found)...done.
Reading symbols from /lib64/libtinfo.so.6...Reading symbols from /lib64/libtinfo.so.6...(no debugging sy
mbols found)...done.
(no debugging symbols found)...done.
Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done.
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Reading symbols from /lib64/libnss_files.so.2...(no debugging symbols found)...done.
0x00007fcfc67cc18a in waitpid () from /lib64/libc.so.6
Missing separate debuginfos, use: dnf debuginfo-install bash-4.4.12-5.fc26.x86_64
(gdb) x/i mmap+76
0x7fcfc680375c <mmap64+76>: retq
[aquila~]$echo$$
9769
[aquila~]$gdb-q
(gdb)附上9769
附加到进程9769
正在从/usr/bin/bash读取符号…正在从/usr/bin/bash读取符号…(未找到调试符号)。。
.完成了。
(未找到调试符号)…完成。
正在从/lib64/libtinfo.so.6读取符号…正在从/lib64/libtinfo.so.6读取符号…(无调试)
mbols发现)…完成。
(未找到调试符号)…完成。
正在从/lib64/libdl.so.2读取符号…(未找到调试符号)…已完成。
正在从/lib64/libc.so.6读取符号…(未找到调试符号)…已完成。
正在从/lib64/ld-linux-x86-64.so.2…读取符号(未找到调试符号)…完成。
正在从/lib64/libnss_文件.so.2…读取符号(未找到调试符号)…已完成。
/lib64/libc.so.6中的waitpid()中的0x00007fcfc67cc18a
缺少单独的debuginfo,请使用:dnf debuginfo安装bash-4.4.12-5.fc26.x86_64
(gdb)x/i mmap+76
0x7FC680375C:retq
我不太确定是否需要
hbreak
,普通的break
也可以。任何问题的线索/答案都非常感谢。它有很多细节,我已经尝试过了。您可以帮助在gdb中设置断点和打印参数。抱歉,我是新来的。一个链接会很好,也许你可以接受它的答案作为一个解决方案,然后?将启用它,如果没有打嗝将标志着它被接受,并有几个其他问题,以及在它。也将等待一段时间,等待任何其他部分答案
[ aquila ~ ] $ echo $$
9769
[ aquila ~ ] $ gdb -q
(gdb) attach 9769
Attaching to process 9769
Reading symbols from /usr/bin/bash...Reading symbols from /usr/bin/bash...(no debugging symbols found)..
.done.
(no debugging symbols found)...done.
Reading symbols from /lib64/libtinfo.so.6...Reading symbols from /lib64/libtinfo.so.6...(no debugging sy
mbols found)...done.
(no debugging symbols found)...done.
Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done.
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Reading symbols from /lib64/libnss_files.so.2...(no debugging symbols found)...done.
0x00007fcfc67cc18a in waitpid () from /lib64/libc.so.6
Missing separate debuginfos, use: dnf debuginfo-install bash-4.4.12-5.fc26.x86_64
(gdb) x/i mmap+76
0x7fcfc680375c <mmap64+76>: retq