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。或者,您可以检查下一个块是否也是空闲的,并将这两个块合并到一个更大的空闲块中(注意页面边框)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)
接收块?您是否有一些前置码或后置码,或者只是一些元数据存储