我正在尝试编写自己的malloc
和free
实现,以便学习,只需mmap
和munmap
(自brk
以来sbrk
已废弃了。我已经阅读了大量有关该主题的文档,但我看到的每个示例都使用sbrk
或者没有很好地解释如何处理大型映射内存区域。
我想写的是这样的想法:我首先绘制一个大区域(即512页);此区域将包含1到992字节之间的所有分配,以16字节为增量。稍后我将使用4096页区域进行更大的分配(如果请求的大小大于页面,则直接使用mmap)。所以我需要一种方法来存储关于我分配或释放的每个块的信息。
我的问题是,如何正确处理这些信息?
我的问题是:如果我创建链表,如何为每个节点分配更多空间?或者我需要将其复制到映射区域吗?如果是这样,我如何在数据空间和预留空间之间徘徊?或者使用静态大小的数组更好?问题在于我的区域大小取决于页面大小。
答案 0 :(得分:7)
顺序(首先适合,最适合)。
创意:使用链接列表,其中最后一个块的大小与页面的剩余大小相符。
struct chunk
{
size_t size;
struct chunk *next;
int is_free;
}
size
太小,next
为NULL),只需mmap一个新页面(可优化:如果大小异常,则生成自定义页面...)is_free
设置为1.可选地,您可以检查下一个块是否也是空闲的,并将它们合并到一个更大的空闲块中(注意页面边框)。优点:易于实施,易于理解,易于调整。
缺点:效率不高(迭代你的整个列表来找到一个块?),需要大量的优化,忙乱的记忆组织
二元伙伴(我喜欢二元算术和递归)
想法:使用2的幂作为大小单位:
struct chunk
{
size_t size;
int is_free;
}
此处的结构不需要next
,如您所见。
原则如下:
实现:
Size
的块
Block_size = 2^k > size + sizeof(chunk)
block_size
is_free
设为1 优点:速度极快,内存效率高,干净。
缺点:复杂,一些棘手的案例(页面边框和好友大小) 需要保留您的网页列表
Buckets(我有很多时间可以输掉)
这是我没有尝试过的三个方法中唯一的方法,所以我只能说理论:
struct bucket
{
size_t buck_num; //number of data segment
size_t buck_size; //size of a data segment
void *page;
void *freeinfo;
}
例如,对于4096字节页面中的512字节存储桶,表示它的位集将是8位位集,
假设*freeinfo = 01001000
,这意味着第二个和第五个桶是免费的。
优点:从长远来看,迄今为止最快,最干净, 在许多小额分配中效率最高
缺点:实现起来非常麻烦,对于小程序而言非常繁重,需要为位集提供单独的内存空间。
可能还有其他算法和实现,但这三种算法和实现最常用,所以我希望你能从中获得想要做的事情。