9

我正在尝试一个简单的 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]
4

3 回答 3

8

既然你在谈论/proc/pid/maps我假设你在linux上。

这就是man malloc我碰巧运行的 linux 发行版告诉我的信息:

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

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

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

如果您真的想看到每次调用 malloc[heap]/proc/pid/maps分配少于 128k。

于 2013-07-22T09:30:41.717 回答
1

所述部分只是没有声明为“堆”,因为它是通过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]部分。由于超出我理解的原因,程序切换到分配 via brk(),这(可能)是堆的来源:

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

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

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

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

因此,更简短的回答:malloc()从 via 获取的 ed 内存brk()位于“真实”[heap]部分,mmap()ed 内存部分未标记为[heap].

于 2013-07-22T08:50:02.050 回答
0

动态分配是通过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

于 2014-10-12T06:05:09.233 回答