【问题标题】:Recoding malloc and size of pages重新编码 malloc 和页面大小
【发布时间】:2014-10-17 17:09:49
【问题描述】:

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

但我不明白我应该如何处理大于页面大小的东西的分配?

【问题讨论】:

    标签: c memory memory-management malloc


    【解决方案1】:

    默认的 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'd 区域,在这种情况下,您需要在单个区域或多个区域中分配。在不更改地址的情况下扩展mmap 区域可能会很困难,这可能会使分配碎片时难以将内存返回给操作系统。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-09
      • 2015-02-28
      • 1970-01-01
      • 2012-10-23
      • 2019-08-10
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      相关资源
      最近更新 更多