Java 使用pmap和gdb查找本机内存泄漏

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

我正在调试java应用程序中的本机内存泄漏。rss每天增长1GB,而堆没有增长。在比较pmap随时间的输出时,我看到在堆的顶部或两个本机库之间添加了多个anon块

 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
  • 我能说sssd_pac_plugin.so和librmi.so之间的内存增加是由它们中的任何一个造成的吗?这个内存分配是连续的吗?

  • 在堆的顶部(地址:00007fc940000000及更高),创建了大量新内存块,范围从126MB到1MB(100个小1MB块附加映像供参考)。它们是表示内存泄漏还是只是为每个新线程创建的

  • 为了查看这些块中的数据,我尝试了下面的代码段,但始终没有得到任何字符串。这都是二进制的,我无法解释。有没有办法把它转换成字符串?或者映射到任何线程/库或任何我可以使用的东西
  • gdb-pid
    转储内存mem.bin 0x00007fc940000000 0x00007fc940000000+126784
    #将文件读取为:
    字符串mem.bin
    
    另一个观察结果是,许多新的块和旧的块增加到大约60-65MB。随着时间的推移,这些块的数量会增加很多。对rss增长的贡献最大。


    我也尝试了libtcmalloc和profilers,主要问题是在生产环境中无法使用它们。在dev实例中,泄漏没有那么严重,因此无法验证探查器的输出。

    一种非常基本的方法:您可以尝试查看谁在调用
    mmap
    (而不是
    munmap

    • 附加到进程中
    • mmap
      上设置断点,使用命令打印参数和回溯(可能5帧)并继续
    • 对于
      munmap
    • 重定向输出
    • 让它运行一天
    • 分离
    • mmap
      s与输出中的
      munmap
      s匹配
    随着
    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