我正在使用mmap函数重新编码malloc 。我正在使用最合适的算法,我能够在一个页面中分配和解除分配。当我想分配小于页面大小时,我的malloc函数运行良好。
但是我不明白我应该如何处理大于页面大小的内容?
答案 0 :(得分:4)
默认的libc malloc实现已经使用mmap
和MAP_ANONYMOUS
分配大量单个内存分配。
要演示,请编译:
#include <stdio.h>
#include <stdlib.h>
int
main (int argc, char **argv)
{
void *i = malloc (100 * 1024 * 1024);
exit (0);
}
然后在strace
下运行
$ strace ./x 2>&1
execve("./x", ["./x"], [/* 21 vars */]) = 0
brk(0) = 0x135d000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7ad0fbb000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=105169, ...}) = 0
mmap(NULL, 105169, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7ad0fa1000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200\30\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1811128, ...}) = 0
mmap(NULL, 3925176, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7ad09dc000
mprotect(0x7f7ad0b91000, 2093056, PROT_NONE) = 0
mmap(0x7f7ad0d90000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x7f7ad0d90000
mmap(0x7f7ad0d96000, 17592, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7ad0d96000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7ad0fa0000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7ad0f9f000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7ad0f9e000
arch_prctl(ARCH_SET_FS, 0x7f7ad0f9f700) = 0
mprotect(0x7f7ad0d90000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ) = 0
mprotect(0x7f7ad0fbd000, 4096, PROT_READ) = 0
munmap(0x7f7ad0fa1000, 105169) = 0
mmap(NULL, 104861696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7aca5db000
exit_group(0) = ?
这一行...
mmap(NULL, 104861696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7aca5db000
...是大块的分配。
答案就在于你的问题。您使用大尺寸MAP_PRIVATE|MAP_ANONYMOUS
分配它。
来自malloc
通常,
malloc()
从堆中分配内存,并调整 使用sbrk
(2)根据需要填充堆的大小。分配块时 内存大于MMAP_THRESHOLD
字节,glibcmalloc()
实现将内存分配为私有匿名映射 使用mmap(2)
。MMAP_THRESHOLD
默认为128 kB,但是 使用mallopt(3)
调整。使用mmap
(2)执行的分配是 不受RLIMIT_DATA
资源限制的影响(请参阅getrlimit
(2))。
来自mallopt
M_MMAP_THRESHOLD
当现有空闲块不能满足大于给定值的分配请求时,保证使用mmap()获得内存。可以使用
mmap()
或sbrk()
分配较小的请求。mmap()
- 分配的内存可以在释放时立即返回给操作系统,但对于分配有sbrk()
的所有内存都不是这样;但是,由mmap()
分配并稍后释放的内存既不会加入也不会被重用,因此开销会更大。默认值:128 * 1024。
M_MMAP_MAX
给定值设置允许在给定时间使用的
mmap()
- 分配的块的最大数量(即使分配请求的大小超过M_MMAP_THRESHOLD
参数的值)。这在mmap()
实现难以扩展的系统上很有用。值为0将禁用mmap()
。默认值:65536。
如果你将M_MMAP_TRESHOLD
调低到零(我不知道它是否会起作用),我猜每个分配都将通过mmap
完成,而不会改变超过mmap
一行代码。但无论如何,您的问题的答案是mmap
,其参数与上述类似。
请注意,可能不希望有太多单独的mmap
d区域,在这种情况下,您需要在单个区域或多个区域内进行分配。增加{{1}}区域而不更改其地址可能会很难,这可能会在分配碎片时使操作系统的内存难以恢复。