0%

malloc实现原理

这篇文章记述了关于 malloc 内存管理的知识点。

http://luodw.cc/2016/02/17/malloc/

首先,我们需要知道,操作系统内核是怎么把一段内存分配给进程的?这当然需要系统调用了。用户态申请分配内容的系统调用是sbrk(n),参数n是期望得到的内存字节数。但是,频繁的调用sbrk进行分配会使得真实内存出现越来越多的零碎空间。Linux操作系统的基本分配方式是伙伴分配方式,所以即使申请的字节数不是2的幂数,系统也会分配出2的幂数的空间来。因此malloc的实现不会是每次都动用内核的。

假设要求分配的块其大小为128个页面,该算法先在块大小为128个页面的链表中查找,看是否有这样一个空闲块。如果有,就直接分配;如果没有,该算法会查找下一个更大的块,在块大小为256个页面的链表中查找一个空闲块。如果存在这样的空闲块,内核就把这256个页面分为两等份,一份分配出去,另一份插入到块大小为128个页面的链表中。如果在块大小为256个页面的链表中也没有找到空闲页块,就继续找更大的块,即512个页面的块。如果存在这样的块,内核就从512个页面的块中分出128个页面满足请求,然后从384个页面中取出256个页面插入到块大小为256个页面的链表中。然后把剩余的128个页面插入到块大小为128个页面的链表中。

malloc采用的总体策略是:
先系统调用sbrk一次,会得到一段较大的并且是连续的空间。进程把系统内核分配给自己的这段空间留着慢慢用。之后调用malloc时就从这段空间中分配,free回收时就再还回来(而不是还给系统内核)。只有当这段空间全部被分配掉时还不够用时,才再次系统调用sbrk。当然,这一次调用sbrk后内核分配给进程的空间和刚才的那块空间一般不会是相邻的。

malloc如何使用得到动态内存空间?一次sbrk之后,malloc就会保留着一段大的连续空间(称作堆空间)。之后对于堆空间malloc不断地分配,free不断地收回,这段空间里的格局必定是“乱七八糟”,有的已分配,有的未分配。

实现动态内存分配往往要考虑以下四个问题:
(1)空闲块组织:我们如何记录空闲块?
(2)选择:我们如何选择一个合适的空闲块来作为一个新分配的块?
(3)分割:在我们选了一个空闲块分配出我们需要的大小之后,我们如何处理这个空闲块中的剩余部分?
(4)合并:我们如何处理一个刚刚被释放的块?
malloc的空闲链表机制:这是对问题(1)的解答。有两种方法:显式空闲链表、隐式空闲链表。

(1)显式空闲链表:用一个链表将可用的内存块连接为一个长长的列表,称为空闲链表。将堆组织成双向空闲链表,每一个空闲块结点都包含一个祖先指针和一个后继指针。链表中的每个结点记录一个连续的、未分配的内存小块。结点的结构很简单,只需要记录可用内存小块的首地址和大小即可。

(2)隐式空闲链表:隐式空闲链表由N个块组成,一个块由头部、有效载荷(只包括已分配的块),以及可能的一些额外的填充(为了保证内存字节对齐而需要的填充)和尾部组成。头部大小为4个字节,在强加双字对齐的约束之后,块大小总是8的倍数,所以用高29位来表示存储块大小,剩余3位中利用最低位来表示块是否已分配(1表示已分配,0表示空闲);尾部和头部的内容一样,加入尾部是为了分配器可以判断出一个块的起始位置和状态。整个堆空间就是一个隐式空闲链表,从低地址向高地址生长,第一个和最后一个8字节标记为已分配,以确定堆的大小。

版权声明:本文为CSDN博主「ojshilu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ojshilu/article/details/17001165

阿里:new 和 malloc 的区别

image-20201111105653421

阿里:如果让你实现malloc,你会怎么实现?

参考https://jacktang816.github.io/post/mallocandfree/

待详细做

new 与 delete

image-20201111204434957

Welcome to my other publishing channels