如何在多线程中关闭malloc()的mmap用法?

时间:2016-12-16 06:07:55

标签: c++ c multithreading malloc mmap

似乎malloc()更喜欢使用mmap()在多线程程序中分配空间。我刚试过设置M_TRIM_THRESHOLDM_MMAP_MAX来关闭mmap用法但失败了:

// Turn off malloc trimming.
mallopt(M_TRIM_THRESHOLD, -1);

// Turn off mmap usage.
mallopt(M_MMAP_MAX, 0);

一段简单的测试代码如下:

#include <malloc.h>
#include <cassert>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

void alloc_assert()
{
    // Turn off malloc trimming.
    mallopt(M_TRIM_THRESHOLD, -1);

    // Turn off mmap usage.
    mallopt(M_MMAP_MAX, 0);

    void* p = malloc(100);

    printf("size_t(p): %zu\n", size_t(p));

    assert(size_t(p) < 0x100000000000l);
}

void* thread_func(void *arg)
{
    alloc_assert();

    pthread_exit(NULL);

    return NULL;
}

int main()
{
    pthread_t thr[2];
    int data = 0;

    // Multi-thread enabled.
    if (pthread_create(&thr[0], NULL, &thread_func, (void*) &data) != 0)
    {
        printf("Create thread error\n");
    }

    pthread_join(thr[0], NULL);

    //alloc_assert();

    return 0;
}

输出如下:

size_t(p): 140154111002816
a.out: main.cpp:37: void alloc_assert(): Assertion `size_t(p) < 0x100000000000l' failed.
[1]    154060 abort      ./a.out

malloc()在高地址而不是普通堆地址上分配空间。但是,如果我们将main()中的代码更改为以下内容:

int main()
{
    alloc_assert();

    return 0;
}

输出结果为:

size_t(p): 31775776

不是使用mmap(),而是malloc()在普通堆上分配空间。我想在多线程程序中关闭mmap() malloc()的使用是否可行?

我的环境配置:

Thread model: posix
gcc version 5.2.0 (GCC)
Linux fsdev32 2.6.32-573.el6.x86_64

1 个答案:

答案 0 :(得分:1)

摘要

看起来原因是glibc的malloc使用了多个malloc“ arenas”,并为每个新线程提供了自己的竞技场,无论您将M_MMAP_MAX设置为什么。

如果该领域有足够的空间,则glibc会将其分配给您的malloc()请求。

您可以使用mallopt(M_ARENA_MAX, 1)禁用它。

详细信息

我通过导入#include <malloc.h>(特定于glibc)并更改代码以显示malloc_stats()统计信息来确认这一点:

malloc_stats();
puts("");
void* p = malloc(100);
malloc_stats();

此打印:

Arena 0:
system bytes     =     135168
in use bytes     =       1328
Total (incl. mmap):
system bytes     =     135168
in use bytes     =       1328
max mmap regions =          0
max mmap bytes   =          0

Arena 0:
system bytes     =     135168
in use bytes     =       1328
Arena 1:
system bytes     =     135168
in use bytes     =       2336
Total (incl. mmap):
system bytes     =     270336
in use bytes     =       3664
max mmap regions =          0
max mmap bytes   =          0

我们可以看到如何添加Arena 1多字节的新135168

strace -fy -e mmap ./yourprogram中,我们可以看到这个竞技场的创建:

[pid  8704] mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7efefe1a7000
[pid  8704] munmap(0x7efefe1a7000, 31821824) = 0
[pid  8704] munmap(0x7eff04000000, 35287040) = 0
[pid  8704] mprotect(0x7eff00000000, 135168, PROT_READ|PROT_WRITE) = 0

size_t(p): 139633681762496; address: 0x7eff000008c0

因此,看起来glibc mmap为新的竞技场分配了一些内存,释放了部分内存,然后mprotect()的{​​{1}}了很多字节-就像那个竞技场显示的一样多像135168中一样。

这向我表明man mallopt在说

malloc_stats()

并非如此:当它想要创建一个新的竞技场时,它仍然会Setting this parameter to 0 disables the use of mmap(2) for servicing large allocation requests.

您显然可以使用以下方法避免这种情况:

mmap