【问题标题】:Implementing your own malloc/free with mmap and munmap使用 mmap 和 munmap 实现自己的 malloc/free
【发布时间】:2012-01-18 12:33:34
【问题描述】:

我已经使用 mmap 自己实现了 ma​​lloc 和 free。现在由于与free不同,munmap 也将长度作为参数,因此我将长度作为附加信息放入映射内存中。

我的 ma​​lloc 和 free 的代码如下所示。我想问一下,这段代码是好的还是我仍然遗漏了什么或以错误的方式做某事。

void * malloc ( size_t size )
{
    int *plen;
    int len = size + sizeof( size ); // Add sizeof( size ) for holding length.

    plen = mmap( 0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );

    *plen = len;                     // First 4 bytes contain length.
    return (void*)(&plen[1]);        // Memory that is after length variable.
}

void free ( void * ptr )
{
    int *plen = (int*)ptr;
    int len;

    plen--;                          // Reach top of memory
    len = *plen;                     // Read length

    munmap( (void*)plen, len );
}

【问题讨论】:

  • 我建议制作一个基本的测试程序,用一堆不同的参数运行这些程序多次,然后通过 Valgrind 运行它,看看是否会出现任何问题。
  • @Paul:仍然无法浏览所有不同的子论坛,从你提到的那个到 SO 的 ubuntu 论坛。您能否建议如何/在哪里获取它们的列表?
  • @gnometorule:点击左侧页面顶部右侧的 StackExchange 字样 - 这将弹出一个窗口 - 然后点击“所有站点”

标签: c linux memory-management x86 mmap


【解决方案1】:

您还应该使用-1 而不是0 作为 mmap 的 fd 参数。

mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)

MAP_ANONYMOUS

映射没有任何文件支持;它的内容被初始化为零。 fd 和 offset 参数被忽略;但是,如果指定了 MAP_ANONYMOUS(或 MAP_ANON),某些实现要求 fd 为 -1,并且可移植应用程序应确保这一点。自内核 2.4 起,Linux 才支持将 MAP_ANONYMOUS 与 MAP_SHARED 结合使用。

【讨论】:

    【解决方案2】:

    一些观察:

    • 您假设int 和size_t 具有相同的大小。如果你想在分配的头部存储一个size_t 值,那么你为什么不这样做呢?为什么要介绍int?
    • 这很可能在内存使用和速度方面都非常低效。 mmap() 的开销很大,通常分配不能小于“页面”。大多数真正的分配器会尝试以各种方式避免在每个 malloc() 上调用操作系统级别的功能。
    • 如果mmap() 失败,它将返回MAP_FAILED,malloc() 也应该如此。因此,您需要在取消引用mmap() 返回的指针之前测试该。
    • 调用free(NULL) 应该是合法的;对于您的实现,它很可能会导致崩溃,因为您在假设它有效之前没有NULL-检查参数。

    【讨论】:

    • 很多时候,在许多 C 程序中,malloc-ed 的大小比一页小得多,因此您必须在一个(或几个连续的)页中保留多个内存块。例如,当您strdup-ing 某个名称或人类语言单词时,典型的大小是一个或几十个字节,但典型的页面大小是 4Kbytes!您还必须接受大型malloc 请求并专门处理它们。
    • @Basile:也就是说,我当前的 PC 的内存是我的第一台 PC 允许某些程序使用的内存的 4096 倍。所以玩具程序可以使用这个分配器运行并不是不可能的,只是不要尝试将 Firefox 链接到它。但是,您真正想要的是每个微不足道的十字节分配两个页,也就是“保护页面之后”;-)
    • 是的,但是您 PC 上的当前软件使用的内存可能比以前使用的多五千。 RAM 就像磁盘空间,它往往是满的......
    • @Basile:我的RAM未满:当前物理内存使用量为50%,大部分可以分页到交换文件。我再说一遍,使用这种荒谬的分配器可以在我的 PC 上运行的程序大小与我的第一台 PC 上可以在常规内存中运行的程序大小大致相当。这并不能使它成为一个好的分配器,只是一个比完全无用的分配器要好。
    • @unwind: mmap 在失败时将返回MAP_FAILED 而不是NULL。
    【解决方案3】:

    您不应该在每次调用自定义 malloc 时都调用 mmap。如前所述,这样做会产生巨大的开销。

    您应该创建一个大型共享内存(例如 4K),并且您的 malloc 函数只需返回您分配的内存范围内的指针。

    然后,如果您的内存不足,您可以创建另外 4k 的共享内存。

    你只需要计算你使用了多少空间并跟踪你的引用,这样释放内存就容易多了。

    【讨论】:

      【解决方案4】:

      至少你应该这样做。

      • 检查mmap 是否失败
      • 为大小存储size_t,而不是int。它们可能不同。
      • 返回合适的对齐内存,这里的内存似乎是 4 字节对齐的(当您从 mmap 向页面对齐数据添加int,大概是 4 字节时。这意味着在返回的内存中存储需要更大对齐的值,例如 double 会导致性能损失,或在某些架构上彻底崩溃。
      • 句柄 NULL 被传递给 free(它应该是一个空操作)

      对于 malloc 实现,我还希望它至少具有基本的调试支持,例如尝试检测双重释放,尝试检测释放无效指针,列出未释放的内存等。

      请记住,您在此处的 malloc 实现可能会非常浪费。如果你 malloc 10 bytes ,你最终将分配 1 页(4096 字节),所有这些都必须映射到物理内存,其余 4082 字节未被使用。

      【讨论】:

        【解决方案5】:

        另请阅读 c malloc on wikipedia 并仔细研究一些真正的 malloc 实现,例如 Doug Lea's malloc。有很多关于这个主题的文献,例如。 by Wolfram Gloger 和许多其他人。

        @MetallicPriest:你真的应该解释更多你在做什么(我对你的工作不太乐观,但你可能会学到很多东西!)

        【讨论】:

        • 访问 Wolfram Gloger 的链接时出现“禁止”错误。您能否链接到一些开放访问文章(如果有)?
        猜你喜欢
        • 1970-01-01
        • 2017-10-11
        • 1970-01-01
        • 2014-11-23
        • 2011-03-22
        • 2020-08-14
        • 1970-01-01
        • 1970-01-01
        • 2017-05-19
        相关资源
        最近更新 更多