2012-02-20 29 views
4

malloc函数同时使用sbrkmmap函数。现在sbrk函数增加或减少数据段。所以它线性增长。现在我的问题是,这种线性是否始终保持不变,或者例如,mmap调用可以分配与数据段重叠的内存?通过mmap分配的内存是否与数据段重叠

我正在讨论在多核系统上运行的多线程程序。关于sbrk用于多线程程序存在一些严重缺陷This blog会谈,并指出,这可能是与sbrk分配的内存可以存储与mmapalloacted间杂的sbrk堆可能变得不连续,因为mmaped区域或共享对象学障碍堆的增长)。

+0

只是要清楚,当你说*线性*,你的意思是*连续性*? – NPE 2012-02-20 18:35:11

+0

是的线性我的意思是连续性。 – MetallicPriest 2012-02-20 18:36:41

回答

11

该博客文章没有看到树木的森林;只允许malloc实现以非零参数调用sbrk。更确切地说,如果应用程序代码调用sbrk非零参数,则Unix的大多数malloc实现将停止正常运行(并且我的意思是“您的程序将崩溃”)。如果你想直接从操作系统做出大量分配,你必须必须使用mmap来做到这一点。

(这是事实,在多线程程序,malloc必须在内部环绕其呼叫互斥sbrk,但是这是一个实现细节。POSIX说malloc是线程安全的,这是一个应用程序的程序员最重要的事情。 )

mmap不会分配内存除非你使用MAP_FIXED重叠brk区域。如果你使用MAP_FIXED并且你的程序爆炸了,你可以保留所有的部分。

内核试图避免这样做,但在正常操作中的mmap可能会分配内存接近brk区域的顶部。如果发生这种情况,随后的sbrk呼叫将与mmap区域发生冲突,将失败。它会而不是分配不连续的内存。 malloc的好实现应该检测到这种情况,并开始使用mmap的一切。我没有真正尝试过,但测试程序很容易编写。

+0

非常好的答案。它清除了我脑海中的混乱。谢谢。 – MetallicPriest 2012-02-20 18:54:31

+1

还要注意,你不知道在实现中调用'malloc'中的哪些函数(例如,在glibc中,甚至是'snprintf'和'dprintf'在内部调用'malloc'来处理格式字符串),所以我会尽可能说除非你的程序只使用异步信号安全函数,否则用非零参数调用'sbrk'是非常不安全的。 – 2012-02-20 19:06:25

3

是这种线性始终保持,或者例如,一个mmap调用可以分配与数据段重叠的内存?

观察到的行为是brk区域总是线性的。实现细节:如果扩大brk区域是不可能的,例如由于阻塞映射,glibc将切换到mmap-only。小分配(< 128KB)似乎是由glibc的通过BRK如果有可能获得,所以阻断有:

#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); 
       } 
     } 
} 

straced时,收益率确实

[...] 
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