Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何通过mmap正确处理内存管理?_C - Fatal编程技术网

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

C 如何通过mmap正确处理内存管理?,c,C,为了学习,我正在尝试编写自己的malloc和free实现,只使用mmap和munmap(因为brk和sbrk已经过时)。我已经阅读了大量关于这个主题的文档,但是我看到的每个示例要么使用sbrk,要么没有很好地解释如何处理映射内存的大区域 我试图写的想法是:我首先绘制一个大区域(即512页);此区域将包含1到992字节之间的所有分配,增量为16字节。稍后我将使用4096页区域进行更大的分配(如果请求的大小大于一页,则直接使用mmap)。所以我需要一种方法来存储关于我分配或释放的每个块的信息 我的问

为了学习,我正在尝试编写自己的
malloc
free
实现,只使用
mmap
munmap
(因为
brk
sbrk
已经过时)。我已经阅读了大量关于这个主题的文档,但是我看到的每个示例要么使用
sbrk
,要么没有很好地解释如何处理映射内存的大区域

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

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

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

基于mmap的malloc有几种可能的实现方式: 顺序(第一次拟合,最佳拟合)。

想法:使用一个链接列表,将最后一块大小调整为页面的剩余大小

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

    缺点:效率不高(迭代整个列表以找到一个块?),需要大量优化,繁忙的内存组织

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

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

    struct chunk
    {
       size_t size;
       int is_free;
    }
    
    正如您将看到的,这里的结构不需要
    下一个

    原则如下:

    • 您有一个4096字节的页面。即(-16表示元数据)4080个可用字节
    • 要分配一个小块,只需将页面分成两个2048字节的块,然后再将前半部分分成1028字节的块。。。直到获得合适的可用空间(最小为32字节(16可用))
    • 每个区块,如果不是一个完整的页面,都有一个伙伴
    • 最终会得到一个树状结构,如下所示:
    • 要访问好友,请在指针和块大小之间使用二进制异或
    实施:

  • 分配大小为
    size
  • 获取所需的
    Block\u size=2^k>size+sizeof(chunk)
  • 在树中找到适合
    块大小的最小可用空间
  • 如果它可以变小,就递归地拆分它
  • 释放一个区块
  • 设置为1是自由的
  • 检查您的好友是否有空(XOR大小,别忘了验证他与您的大小相同)
  • 如果他是的话,就把他的身材翻一倍。重现
  • 优点:速度极快,内存效率高,干净

    缺点:复杂,一些棘手的情况(页面边框和好友大小) 需要保留你的页面列表吗

    桶(我有很多时间要浪费)

    这是三种方法中我自己没有尝试过的唯一方法,因此我只能说理论:

    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
    ,这意味着第二个和第五个桶是免费的

    优点:从长远来看,它是迄今为止最快、最干净的, 在许多小型分配中最有效

    缺点:实现起来非常麻烦,对于一个小程序来说相当沉重,需要为位集提供单独的内存空间


    可能还有其他算法和实现,但这三种算法和实现是最常用的,因此我希望您能从中了解您想要做什么。

    我写道。对于分配集合大小的内存区域块(例如,所有16字节大小的分配,或所有32字节大小的分配),位图在执行内存开销时可能比链表更好地执行(链表对于每个分配可能需要16字节,只是为了维持一些SSE操作所需的16字节内存对齐)…我对64位机器使用了8字节对齐(忽略SSE)。这在很大程度上取决于定制分配器为应用程序设计的特定问题,并且基本上是一个数据结构问题,与作为基本分配器的
    mmap
    的具体使用正交,除非您开始玩虚拟内存技巧。您能详细说明一下您的分配模式是什么样子的吗?物理内存、地址空间或时间是否稀缺?您是否需要硬时间/空间/碎片保证?压实可行吗?无论如何,通常都会将元数据作为块头存储在内部。关于buddy分配器:如何从行指针
    free(void*p)
    接收块?您是否有一些前置码或后置码,或者只是一些元数据存储