从 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 定义了 arena 的最大大小,基本上 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() 时,主 arena 分配了 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() ,您可以很容易地看到内存消耗的变化。