似乎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): %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
答案 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