通过mmap分配的内存是否可以与数据段重叠

时间:2012-02-20 18:32:43

标签: c linux gcc

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

我在谈论在多核系统上运行的多线程程序。 This blog讨论了多线程程序sbrk的一些严重缺陷,并指出分配有sbrk的内存可能与与mmap同步的内存混合在一起({1}} sbrk堆可能会变得不连续,因为mmaped区域或共享对象会阻碍堆的增长

2 个答案:

答案 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