顶部内存泄漏分析

时间:2018-12-05 13:57:30

标签: c++ memory-leaks memoryanalyzer

我想使用“ top”工具来分析进程的内存消耗和可能的内存泄漏。 为此,我编写了这个程序(程序名:memoryTest):

int main(){
char* q;
for(int i=0; i<100; i++){
    q = (char*) malloc(1024); 
    sleep(1);
}
return 0;   

}

首先,我现在可以观看该节目, 通过在所述过程之后使用选项“ o”和过滤器规范“ COMMAND = memoryTest”进行过滤,但是我发现该过程的内存消耗没有变化。 我在这里有个愚蠢的错误吗?

3 个答案:

答案 0 :(得分:0)

尝试以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(){
  char* q;
  for(int i=0; i<10000; i++){
    q = (char*)malloc(1024); 
    memset(q,0,1024);
  }
  getchar();
  return 0;
}

for循环中的不同值。

这里的问题是,即使在实际填充Linux之前,Linux也不必使用内存。因此,您需要将数据写入要分配的内容,否则可能甚至无法注册该内存正在使用中。这就是为什么某些应用程序可以分配内存的原因,这很好,然后即使分配了内存,当他们开始使用内存时,他们仍会发现内存不可用。

memset将强制将零写入写入已分配的缓冲区,从而导致使用内存并将其注册为顶部使用状态。请注意,在这里使用htop可能会更方便。

如果您想进一步研究Linux特色的“乐观的malloc”,请注意,其他一些操作系统也不会有这种行为。

还值得指出的是,内部内存是按一定大小的连续块分配的。因此,如果以最小的块大小(例如4k)分配内存,则分配额外的1KB可能不会增加大小。

答案 1 :(得分:0)

在malloc手册页中:

  
    

通常,malloc()从堆中分配内存,并调整            使用sbrk(2)根据需要调整堆的大小。分配块时            大于MMAP_THRESHOLD字节的内存,glibc malloc()            实现将内存分配为私有匿名映射            使用mmap(2)。 MMAP_THRESHOLD默认为128 kB,但是            可使用mallopt(3)进行调整。在Linux 4.7之前的分配            使用mmap(2)执行的操作不受RLIMIT_DATA资源的影响            限制;从Linux 4.7开始,此限制也适用于分配            使用mmap(2)执行。

  

内存池称为arenas,实现在arena.c中。 宏HEAP_MAX_SIZE定义了竞技场的最大大小,它在32位上基本上是1MB,在64位上基本上是64MB:

HEAP_MAX_SIZE = (2 * DEFAULT_MMAP_THRESHOLD_MAX)
32-bit [DEFAULT_MMAP_THRESHOLD_MAX = (512 * 1024)] = 1,048,576 (1MB)
64-bit [DEFAULT_MMAP_THRESHOLD_MAX = (4 * 1024 * 1024 * sizeof(long))] = 67,108,864 (64MB)

堆实现(arena.c)中的信息:

  

/ *堆是一个单独的连续内存区域,该区域包含(可分配)malloc_chunks。它是使用mmap()分配的,并且始终从与HEAP_MAX_SIZE对齐的地址开始。 * /

编辑:

可以使用 strace 来观察堆分配。在对brk()的第一次调用中,主舞台分配了200K字节(来自libstdc ++的72K和128K top_pad)。

brk(NULL)                               = 0x556ecb423000 -> current program break
brk(0x556ecb455000)                     = 0x556ecb455000 -> resize the heap by moving brk 0x32000 bytes upward (main arena initialization with 200K). 
write(1, "i = 0\n", 8)                = 8
...
write(1, "i = 123\n", 8)                = 8     
brk(0x556ecb476000)                     = 0x556ecb476000 -> resize the heap by moving brk 0x21000 bytes upward (growing heap 128K). 
...
write(1, "i = 252\n", 8)                = 8
brk(0x556ecb497000)                     = 0x556ecb497000 -> resize the heap by moving brk 0x21000 bytes upward (growing heap 128K). 

您的应用程序仅使用了100K字节的128K可用堆,因此top或htop程序不会观察到内存消耗。

如果通过请求大于128K的块或增加块数(> 128)来强制glibc使用mmap(),则可以轻松地看到内存消耗的变化。

答案 2 :(得分:0)

如果您想了解内存使用情况,请不要使用top。使用免费的开源程序https://github.com/vmware/chap(免责声明:我是原始开发人员)。

只需在程序完成之前收集活动内核,例如通过运行gcore,然后键入:

您的核心文件名

然后您可以执行以下操作:

计数泄漏 清单泄漏 计数使用 免费计数 ....

以下是使用您的程序的示例,在30秒后收集了内核:

-bash-4.1$ ./q53633998 &
[1] 18014
-bash-4.1$ sleep 30
gcore 18014
-bash-4.1$ gcore 18014
0x00000030ed6aca20 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-         template.S:82
82      T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
Saved corefile core.18014
-bash-4.1$ ~/public_html/chap core.18014
chap> count used
36 allocations use 0x9120 (37,152) bytes.
chap> count free
1 allocations use 0x17db0 (97,712) bytes.
chap> count leaked
35 allocations use 0x8d18 (36,120) bytes.
chap> count anchored
1 allocations use 0x408 (1,032) bytes.
chap> list anchored
Used allocation at 19d4e40 of size 408

1 allocations use 0x408 (1,032) bytes.
chap> explain 19d4e40
Address 19d4e40 is at offset 0 of
an anchored allocation at 19d4e40 of size 408
Allocation at 19d4e40 appears to be directly anchored from at least one stack.
Address 0x7ffc88570270 is on the live part of the stack for thread 1.
Stack address 7ffc88570270 references 19d4e40

chap> list leaked
Used allocation at 19cc010 of size 408

Used allocation at 19cc420 of size 408

Used allocation at 19cc830 of size 408

Used allocation at 19ccc40 of size 408

Used allocation at 19cd050 of size 408

Used allocation at 19cd460 of size 408

Used allocation at 19cd870 of size 408

Used allocation at 19cdc80 of size 408

Used allocation at 19ce090 of size 408

Used allocation at 19ce4a0 of size 408

Used allocation at 19ce8b0 of size 408

Used allocation at 19cecc0 of size 408

Used allocation at 19cf0d0 of size 408

Used allocation at 19cf4e0 of size 408

Used allocation at 19cf8f0 of size 408

Used allocation at 19cfd00 of size 408

Used allocation at 19d0110 of size 408

Used allocation at 19d0520 of size 408

Used allocation at 19d0930 of size 408

Used allocation at 19d0d40 of size 408

Used allocation at 19d1150 of size 408

Used allocation at 19d1560 of size 408

Used allocation at 19d1970 of size 408

Used allocation at 19d1d80 of size 408

Used allocation at 19d2190 of size 408

Used allocation at 19d25a0 of size 408

Used allocation at 19d29b0 of size 408

Used allocation at 19d2dc0 of size 408

Used allocation at 19d31d0 of size 408

Used allocation at 19d35e0 of size 408

Used allocation at 19d39f0 of size 408

Used allocation at 19d3e00 of size 408

Used allocation at 19d4210 of size 408

Used allocation at 19d4620 of size 408

Used allocation at 19d4a30 of size 408

35 allocations use 0x8d18 (36,120) bytes.
chap> list free
Free allocation at 19d5250 of size 17db0

1 allocations use 0x17db0 (97,712) bytes.
chap>

最后一个“空闲”分配是在第一个malloc调用期间分配的内存块的尾部,并在随后的malloc调用进行时逐渐积累。

当然,还有其他工具(例如valgrind)可以通过对流程进行检测来发挥不同的作用,但是如果您想要一个可以在不更改流程运行方式的情况下分析流程内存使用情况的工具,chap是一个不错的选择