【问题标题】:missing [heap] section in /proc/pid/maps/proc/pid/maps 中缺少 [heap] 部分
【发布时间】:2013-07-22 07:59:27
【问题描述】:

我正在试验一个不断分配内存的简单 C 程序:

for ( i = 0; i < 10000; i ++ )
{
    array[i] = malloc( 1024*1024 );
    if ( array[i] == NULL )
    {
        break;
    }
    printf("Sleeping...%d\n", i);
    sleep( 60 );
}

此处粘贴完整代码:http://tny.cz/2d9cb3df

但是,当我 cat /proc/pid/maps 时,我没有得到 [heap] 部分。为什么?

08048000-08049000 r-xp 00000000 08:11 17         /data/a.out
08049000-0804a000 r--p 00000000 08:11 17         /data/a.out
0804a000-0804b000 rw-p 00001000 08:11 17         /data/a.out
0804b000-0805e000 rw-p 00000000 00:00 0 
b74c6000-b75c8000 rw-p 00000000 00:00 0 
b75c8000-b7775000 r-xp 00000000 08:01 3539272    /lib/i386-linux-gnu/libc-2.17.so
b7775000-b7777000 r--p 001ad000 08:01 3539272    /lib/i386-linux-gnu/libc-2.17.so
b7777000-b7778000 rw-p 001af000 08:01 3539272    /lib/i386-linux-gnu/libc-2.17.so
b7778000-b777b000 rw-p 00000000 00:00 0 
b7797000-b779a000 rw-p 00000000 00:00 0 
b779a000-b779b000 r-xp 00000000 00:00 0          [vdso]
b779b000-b77bb000 r-xp 00000000 08:01 3539289    /lib/i386-linux-gnu/ld-2.17.so
b77bb000-b77bc000 r--p 0001f000 08:01 3539289    /lib/i386-linux-gnu/ld-2.17.so
b77bc000-b77bd000 rw-p 00020000 08:01 3539289    /lib/i386-linux-gnu/ld-2.17.so
bff21000-bff42000 rw-p 00000000 00:00 0          [stack]

【问题讨论】:

  • 编译器推断for循环没有做任何事情(即无操作)并对其进行优化?
  • @H2CO3,我改了打印分配的地址还是一样。
  • @H2CO3 即使对于过于激进的优化编译器来说,这似乎也是一个巨大的飞跃,因为循环包含对具有相当大副作用的函数的三个调用。
  • @JoachimPileborg 好吧,是的,很公平。 (但我也看到了 GCC 和 clang 产生的“更糟糕”的优化......)
  • @Mat 代码链接已添加。

标签: c memory


【解决方案1】:

既然您在谈论 /proc/pid/maps,我假设您使用的是 linux。

这是man malloc 在我碰巧运行的 linux 发行版上告诉我的:

通常,malloc() 从堆中分配内存,并根据需要调整堆的大小,使用 sbrk(2)

当分配大于MMAP_THRESHOLD 字节的内存块时,glibc malloc() 实现使用mmap(2) 将内存分配为私有匿名映射。 MMAP_THRESHOLD 默认为 128 kB,但可使用 mallopt(3) 进行调整。

使用mmap(2) 执行的分配不受RLIMIT_DATA 资源限制的影响(请参阅getrlimit(2))。

如果你真的想在你的/proc/pid/maps 中看到[heap],那么每次调用 malloc 时分配少于 128k。

【讨论】:

    【解决方案2】:

    上述部分只是没有声明为“堆”,因为它是通过mmap() 调用分配的。

    在我的 64 位系统上,分配的内存来自这个不断增长的部分:

    7f7fbda7a000-7f7fbdc7c000 rw-p 00000000 00:00 0
    ...
    7f7fbc868000-7f7fbdc7c000 rw-p 00000000 00:00 0
    ...
    7f7fbc363000-7f7fbdc7c000 rw-p 00000000 00:00 0
    

    段在开始处扩展,新分配的内存总是起始地址+0x10。

    内存分配器在这里做的是

    mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7fbb353000
    

    奇怪的东西;我会怀疑每个mmap()ed 内存部分都是单独显示的。但如果我让程序执行中间的free() 调用,内存分配如下:

    7f16be944000-7f16bec47000 rw-p 00000000 00:00 0
    7f16bed48000-7f16bee49000 rw-p 00000000 00:00 0
    

    在原本连续的内存中出现了一个洞。

    另外发生了一件事情:在这个修改后的程序中,确实有一个[heap] 部分。由于超出我理解的原因,程序切换到通过brk() 进行分配,这(可能)是堆的来源:

    每次调用brk(),相应的部分都会在其末尾扩展:

    01183000-029a4000 rw-p 00000000 00:00 0                                  [heap]
    

    我不知道是什么改变了malloc() 的想法,将“真正的”堆(连接到brk() 的东西)用于分配。第一个 munmap() 调用,与各自的 free() 相关,似乎产生了这个。

    根据thismmap()ed 块似乎有一个最大值。如果超过这个值,gnulibc 会退回到brk()/sbrk(),它在“常规堆区域”上运行。

    所以,更简短的回答:通过brk() 获取的malloc()ed 内存位于“真实”[heap] 部分,mmap()ed 内存部分未标记为[heap]

    【讨论】:

      【解决方案3】:

      使用brk() 调用进行动态分配。 .brk 部分的开始是在程序加载期间计算的(查看 /linux/fs/binfmt_elf.c 中的 load_elf_binary())。但是,直到在运行时请求实际分配时才映射页面。请参阅下面的 /proc/pid/maps 在 x86_64 系统上分配前后的屏幕显示

      在调用 calloc(8032,1) 之前:

      $ cat /proc/$(pid)/maps
      
      00400000-00401000 r-xp 00000000 08:02 1314308             /testheap
      
      00600000-00601000 r--p 00000000 08:02 1314308             /testheap
      
      00601000-00602000 rw-p 00001000 08:02 1314308             /testheap
      
      7fafeea3e000-7fafeebfb000 r-xp 00000000 08:02 198420      /lib/x86_64-linux-gnu/libc-2.17.so
      
      7fafeebfb000-7fafeedfb000 ---p 001bd000 08:02 198420      /lib/x86_64-linux-gnu/libc-2.17.so
      

      调用 calloc(8032,1) 后:

      $cat /proc/$(pid)/maps
      
      00400000-00401000 r-xp 00000000 08:02 1314308             /testheap
      
      00600000-00601000 r--p 00000000 08:02 1314308             /testheap
      
      00601000-00602000 rw-p 00001000 08:02 1314308             /testheap
      
      **021ea000-0220c000 rw-p 00000000 00:00 0                   [heap]**
      
      7fafeea3e000-7fafeebfb000 r-xp 00000000 08:02 198420      /lib/x86_64-linux-gnu/libc-2.17.so
      
      7fafeebfb000-7fafeedfb000 ---p 001bd000 08:02 198420      /lib/x86_64-linux-gnu/libc-2.17.so
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多