重新编码malloc和页面大小

时间:2014-10-17 17:09:49

标签: c memory memory-management malloc

我正在使用mmap函数重新编码malloc 。我正在使用最合适的算法,我能够在一个页面中分配和解除分配。当我想分配小于页面大小时,我的malloc函数运行良好。

但是我不明白我应该如何处理大于页面大小的内容?

1 个答案:

答案 0 :(得分:4)

默认的libc malloc实现已经使用mmapMAP_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字节,glibc malloc()   实现将内存分配为私有匿名映射   使用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}}区域而不更改其地址可能会很难,这可能会在分配碎片时使操作系统的内存难以恢复。