似乎malloc()
更喜欢使用mmap()
在多线程程序中分配空间。我刚刚尝试设置M_TRIM_THRESHOLD
并M_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): %zun", 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 errorn");
}
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
malloc()
没有使用mmap()
,而是在普通堆上分配了空间。我想是否可以关闭多线程程序中malloc()
mmap()
的使用?
我的环境配置:
Thread model: posix
gcc version 5.2.0 (GCC)
Linux fsdev32 2.6.32-573.el6.x86_64
总结
看起来原因是glibc的malloc使用了多个malloc"竞技场",并为每个新线程提供了自己的竞技场,无论您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
我们可以看到如何添加具有135168
字节的新Arena 1
。
在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
所以看起来glibcmmap
新竞技场的一些内存,释放它的一部分,然后mprotect()
135168
许多字节 - 就像那个竞技场显示的一样多malloc_stats()
。
这向我表明man mallopt
说
Setting this parameter to 0 disables the use of mmap(2)
for servicing large allocation requests.
并不完全正确:当它想要创建一个新竞技场时,它仍然会mmap
。
您显然可以使用以下方法避免这种情况:
mallopt(M_ARENA_MAX, 1);