如何通过mmap正确处理内存管理?

时间:2016-12-12 15:13:15

标签: c

我正在尝试编写自己的mallocfree实现,以便学习,只需mmapmunmap(自brk以来sbrk已废弃了。我已经阅读了大量有关该主题的文档,但我看到的每个示例都使用sbrk或者没有很好地解释如何处理大型映射内存区域。

我想写的是这样的想法:我首先绘制一个大区域(即512页);此区域将包含1到992字节之间的所有分配,以16字节为增量。稍后我将使用4096页区域进行更大的分配(如果请求的大小大于页面,则直接使用mmap)。所以我需要一种方法来存储关于我分配或释放的每个块的信息。

我的问题是,如何正确处理这些信息?

我的问题是:如果我创建链表,如何为每个节点分配更多空间?或者我需要将其复制到映射区域吗?如果是这样,我如何在数据空间和预留空间之间徘徊?或者使用静态大小的数组更好?问题在于我的区域大小取决于页面大小。

1 个答案:

答案 0 :(得分:7)

基于mmap的malloc有几种可能的实现方式:

顺序(首先适合,最适合)。

创意:使用链接列表,其中最后一个块的大小与页面的剩余大小相符。

struct chunk
{
   size_t size;
   struct chunk *next;
   int is_free;
}
  1. 分配
    1. 迭代您的列表以获得合适的免费块(可优化)
    2. 如果找不到任何内容,请将最后一个块调整大小为所需大小,并创建剩余大小的空闲块。
    3. 如果到达页面末尾(size太小,next为NULL),只需mmap一个新页面(可优化:如果大小异常,则生成自定义页面...)
  2. 要自由,甚至更简单:只需将is_free设置为1.可选地,您可以检查下一个块是否也是空闲的,并将它们合并到一个更大的空闲块中(注意页面边框)。
  3. 优点:易于实施,易于理解,易于调整。

    缺点:效率不高(迭代你的整个列表来找到一个块?),需要大量的优化,忙乱的记忆组织

    二元伙伴(我喜欢二元算术和递归)

    想法:使用2的幂作为大小单位:

    struct chunk
    {
       size_t size;
       int is_free;
    }
    

    此处的结构不需要next,如您所见。

    原则如下:

    • 您有一个4096字节的页面。即(元数据为-16)4080个可用字节
    • 要分配一个小块,只需将页面拆分为两个2048字节块,然后再分割1028字节块中的前半部分......直到获得合适的可用空间(最小为32字节(16)可用))。
    • 每个街区,如果不是整页,都有一个好友。
    • 你最终会得到像这样的树状结构: like this
    • 要访问您的好友,请在指针和块大小之间使用二进制XOR。

    实现:

    1. 分配大小为Size的块
      1. 获取所需的Block_size = 2^k > size + sizeof(chunk)
      2. 找到适合block_size
      3. 的树中的最小可用空间
      4. 如果它变小,可以递归拆分。
    2. 释放一个街区
      1. is_free设为1
      2. 检查你的好友是否有空(XOR大小,不要忘记确认他和你一样大小)
      3. 如果他是,他的身材加倍。递归。
    3. 优点:速度极快,内存效率高,干净。

      缺点:复杂,一些棘手的案例(页面边框和好友大小)       需要保留您的网页列表

      Buckets(我有很多时间可以输掉)

      这是我没有尝试过的三个方法中唯一的方法,所以我只能说理论:

      struct bucket
      {
        size_t buck_num;  //number of data segment
        size_t buck_size; //size of a data segment
        void *page;
        void *freeinfo;
      }
      
      • 你从一开始就有几个小页面,每个小页面分成不变大小的块(一个8字节页面,一个16字节,一个32字节等等)
      • 这些数据桶的“自由信息”存储在每个页面开头的位集(代表大量整数的结构)中,或存储在单独的存储区中。

      例如,对于4096字节页面中的512字节存储桶,表示它的位集将是8位位集, 假设*freeinfo = 01001000,这意味着第二个和第五个桶是免费的。

      优点:从长远来看,迄今为止最快,最干净,       在许多小额分配中效率最高

      缺点:实现起来非常麻烦,对于小程序而言非常繁重,需要为位集提供单独的内存空间。

      可能还有其他算法和实现,但这三种算法和实现最常用,所以我希望你能从中获得想要做的事情。