malloc的底层原理和流程


前言:从malloc的内存方式、内存池管理、brk系统调用过程这三个点,讲述malloc系统调用的底层原理和流程。

一、malloc的内存申请方式

malloc申请内存有两种,申请小于128KB的内存是用brk系统调用,申请大于128KB就是用mmap的匿名映射。(brk和mmap申请的都是懒分配内存,只有真正访问时才分配物理内存)

  • 为什么要有brk方式

mmap是系统调用,频繁的系统调用会让CPU性能下降。所以就通过brk系统调用,每次malloc申请内存时,brk会给malloc分配比所需内存更大的内存池,然后malloc后面就可以自己操作内存池来申请或释放内存,而无需再调用系统调用。所以对于brk方式的malloc,使用free并不会直接将内存归还系统,而是留在内存池等进程结束才归还。

二、malloc的内存池管理

注1:只有brk方式申请的内存会有内存池机制,mmap并没有这个机制。
注2:下面只是简单说明malloc内存管理最主要的机制,省略了一些其他的机制或细节

1、分级内存池

malloc使用分级线程池,将不同大小的内存块分为不同等级,每个等级有对应的一个空闲链表来管理。malloc会根据每次请求的大小来选择合适的级别,从链表中分配内存。链表的遍历可以是从头到尾找到第一个满足请求的大小进行分配,也可以是找到大小最接近的块来分配。

2、内存块信息

在每块内存的开头处会有对应的内存块信息,包括内存块的大小、空闲链表的下一块内存的指针、以及内存是否被分配。free调用就是根据这里来得知释放内存的大小。

3、内存块合并

当内存块被释放时,如果相邻块也是空闲的,malloc会进行块合并来减少内存碎片。在高频率的内存分配和释放场景中,这个操作会影响性能

4、内存块分割

当 malloc在空闲链表中找到一个比请求大小大的空闲块时,它可能会将这个块分割成两部分,一部分分配给请求的内存,另一部分仍然保持空闲状态。但这个频繁的分割操作可能会导致小的内存块散布在内存中,增加内存碎片化

三、brk的内存分配过程

对于malloc,brk每次以页为单位来给malloc分配内存池,之后让malloc自己管理和操作内存池的内存,直到内存池不够了再调用brk来扩充内存池。brk分配内存的大致过程就是将堆区内存向上扩展,具体流程这里以xv6操作系统为例(一个类Unix的简单系统)。注:看懂这里需要有一定的页表基础

1、空闲链表

和malloc的内存池管理方式类似,xv6系统在每个空闲页面的内存开头处存放一个run结构体,该结构体存储着一个指向下个空闲页起始地址的指针next。由于run的地址和页面地址相同,所以xv6可以通过遍历run链表来找到所有空闲页。这个run链表叫做allocator分配器。

2、sbrk

sbrk是xv6系统中的系统调用,用于给进程增加或减少堆区内存。分配内存主要就是做两件事:1、从空闲链表中删除一张空闲内存页并返回给进程;2、把内存页的虚拟地址和物理地址的映射关系写到页表PTE上并设置标志位。减小内存同理,主要就是:1、把对应页表项清空(设置PTE_V);2、根据该页面的物理地址创建run结构体并插入空闲链表。

四、malloc的缺陷

1、不支持多线程环境;2、由于内存块分割操作,频繁malloc会导致内存碎片化;3、由于内存块合并操作,频繁free会一直触发影响性能。

解决方法:自己实现一个内存池来替代malloc

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值