malloc
函数同时使用sbrk
和mmap
函数。现在sbrk
函数增加或减少数据段。所以它线性增长。现在我的问题是,是否始终保持线性,或者例如mmap
调用可以分配与数据段重叠的内存?
我在谈论在多核系统上运行的多线程程序。 This blog讨论了多线程程序sbrk
的一些严重缺陷,并指出分配有sbrk
的内存可能与与mmap
同步的内存混合在一起({1}} sbrk
堆可能会变得不连续,因为mmaped
区域或共享对象会阻碍堆的增长。
答案 0 :(得分:12)
那篇博文没有看到树林;只允许malloc
实现使用非零参数调用sbrk
。更确切地说,如果应用程序代码使用非零参数调用malloc
,则Unix的大多数sbrk
实现将停止正常运行(并且我的意思是“您的程序将崩溃”)。如果您想直接从操作系统进行大量分配,则必须使用mmap
来执行此操作。
(确实,在多线程程序中,malloc
必须在其sbrk
的调用内部包含一个互斥锁,但这是一个实现细节.POSIX说malloc
是线程安全,这对应用程序员来说非常重要。)
mmap
,否则 brk
将不会分配内容重叠 MAP_FIXED
区域。如果您使用MAP_FIXED
并且程序爆炸,您可以保留所有部分。
内核试图避免这样做,但正常操作中的mmap
可能会在靠近brk
区域顶部的位置分配内存。如果发生这种情况,则与sbrk
区域发生冲突的后续mmap
来电将失败。它将不分配不连续的内存。 malloc
的良好实现应该检测到这种情况并开始使用mmap
来处理所有事情。我实际上没有尝试过,但测试程序很容易编写。
答案 1 :(得分:3)
是否始终保持线性,或者例如,mmap调用可以分配与数据段重叠的内存?
观察到的行为是brk区域始终是线性的。实现细节:如果无法扩大brk区域,例如由于阻塞映射,glibc将切换到仅mmap。如果可能的话,似乎可以通过glibc通过brk获得小的分配(<128KB),所以用以下方法阻止它:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
int main(void)
{
int i;
for (i = 0; i < 1024; ++i) {
malloc(2048);
if (i == 512) {
void *r, *end = sbrk(0);
r = mmap(end, 4096, PROT_NONE,
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
}
}
}
当被束缚时,确实是收益率
[...]
brk(0x1e7d000) = 0x1e7d000
mmap(0x1e7d000, 4096, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0x1e7d000
brk(0x1e9e000) = 0x1e7d000 <-- (!)
mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbfd9bc9000