malloc底层实现

Linux维护一个break指针,这个指针指向堆空间某个位置。从堆起始地址到break之间的地址空间为映射好的,可以供进程访问
而从break往上,是未映射的地址空间,如果访问这段空间则程序会报错。我们使用malloc进行内存分配就是从break往上进行的

而rlimit则是限制进程堆内存容量的指针,即可分配堆空间的“极限指针”

获取了break地址,也就是内存申请的初始地址

Linux通过brk和sbrk系统调用操作break指针

int brk(void *addr);
void *sbrk(intptr_t increment);
// brk将break指针直接设置为某个地址:brk在执行成功时返回0,否则返回-1并设置errno为ENOMEM
// sbrk将break从当前位置移动increment所指定的增量:sbrk成功时返回break移动之前所指向的地址,否则返回(void *)-1。如果将increment设置为0,则可以获得当前break的地址

在操作系统角度来看,分配内存有两种方式

  • 一种是采用推进brk指针来增加堆的有效区域来申请内存空间
  • 另一种是采用mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存
    这两种方式都是分配虚拟内存,只有当第一次访问虚拟地址空间时,操作系统给分配物理内存空间
    malloc是采用brk的方式来动态分配内存

malloc基本的实现原理就是维护一个内存空闲链表,当申请内存空间时,搜索内存空闲链表,找到适合的空闲内存空间,然后将空间分割成两个内存块,一个变成分配块,一个变成新的空间块
如果没有找到,那么就会用sbrk()推进break指针来申请内存空间

分配空闲块

所要申请的内存是由多个内存块构成的链表

内存块的大致结构如下:

typedef struct s_block *t_block;
struct s_block 
{
    size_t size; /* 数据区大小 */
    t_block next; /* 指向下个块的指针 */
    int free; /* 是否是空闲块 */
    int padding; /* 填充4字节,保证meta块长度为8的倍数 */
    char data[1] /* 这是一个虚拟字段,表示数据块的第一个字节,长度不应计入meta */
};

搜索空闲块最常见的算法有:首次适配,下一次适配,最佳适配。
首次适配:第一次找到足够大的内存块就分配,这种方法会产生很多的内存碎片
下一次适配:也就是说等第二次找到足够大的内存块就分配,这样会产生比较少的内存碎片
最佳适配:对堆进行彻底的搜索,从头开始,遍历所有块,使用数据区大小大于size且差值最小的块作为此次分配的块

首次适配(First fit)更好的运行效率
最佳适配(Best fit)较高的内存使用率

如果现有block都不能满足待申请size的要求,则需要在链表最后开辟一个新的block,使用sbrk()进行创建新的block

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值