malloc 堆分配算法探析

提到 C 语言不能不说内存管理,而内存管理则必须了解 malloc,今天深度学习了 malloc 的堆分配算法原理,笔记整理如下

什么是堆分配算法?
程序向操作系统申请一块适当大小的堆空间,然后由程序自己管理这块空间,而具体来讲,管理着堆空间分配的是运行库------也就是封装起来的 malloc 函数。运行库相当于向操作系统“批发”了一块较大的堆空间,然后“零售”给程序使用,当全部“售完”或程序有大量的内存需求时,再根据实际情况向操作系统“进货”。当运行库在向程序零售堆空间时,必须管理它批发来的堆空间,不能重复“出售”,导致地址冲突,于是运行库需要一个算法来管理堆空间,这个算法就是堆的分配算法。

常见的 malloc 分配算法三种:空闲链表、位图、对象池

1. 空闲链表

空闲链表的方法实际就是把堆上各个空闲的块按照链表的方式连接起来,当用户需要一块空间时,遍历整个链表,直到找到合适的大小将他拆分;当用户释放空间则进行合并。

空闲链表的结构: 头 + 空闲块
头结构记录了上一个 [pre] 和下一个 [next] 空闲块的地址

如何利用这个结构分配空间?
首先在空闲链表中查找足够容纳请求大小的一个空闲块,然后将这个块分为两部分,一部分为程序请求的空间,另一部分为剩余下来的空闲空间。

释放空间的时候,只有一个指针,无法确定这个块的大小,如何释放
当用户请求 k 个字节空间的时候,实际分配 k+4 个字节,多于的 4 个字节用于存储分配的空间大小。
注意:记录空闲块大小的 4 个字节容易被越界读写从而遭受破坏,整个堆就无法操作.

2.位图

其核心思想是将整个堆分为大量的,每个块的大小相同。当用户请求内存的时候,总是分配整数个块的数据:第一个块称为已分配区域的,其余的称为已分配区域的主体。可以用一个整数数组来记录块的使用情况。

由于每个块只有头/主体/空闲三种状态,因此用两个位可以表示一个块。11表示头,10表示主体,00表示空闲
比如堆的大小有 1MB,一个块的大小为 128B,总共有 1MB/128B=8K,可以用 8K*2/8=2KB大小的位图来表示。

优点

  1. 速度快:通过位图的特性,存储在一个数组内
  2. 稳定性好:避免用户越界读写破坏数据
  3. 每个块都必有一种状态,不需要额外信息

缺点

  1. 分配内容容易产生碎片,大小不足整数个块就会浪费
  2. 如果堆太大,而设定的块很小,那么位图将会很大
3. 对象池

在一些特定场合,被分配对象的大小经常是固定的几个值,针对这种情况设计一个更为高效的堆分配算法:如果每一次分配的空间大小都一样,可以按照这个标准为一个单位,将整个堆空间划分为大量的小块,每次请求只需要找到一个小块就可以了。
对象池的管理方法,可以采用空闲链表,也可以采用位图。

4. 其它

对于 Glibc 来说,对于 <64B 的空间申请采用类似于对象池的方法,对于 >512B 自己的空间申请采用最佳适配算法;对于 64B<512B 的根据情况选择;对于 >128KB 的申请,使用 mmap 机制直接向操作系统申请空间

Linux下两种对空间分配的方式

1.brk()系统调用

int brk(void end_data_seqment).*
brk 实际就是通过设置数据段的结束地址,来扩大堆或者虽小堆空间。Glibc中有一个函数 sbrk,它的功能与 brk 类似,只是参数和返回值有差别,sbrk 以一个增量为参数,即需要增加或减少(负数)的空间大小,返回最终数据段的结束地址。

2.mmap()系统调用

void* mmap(void* start, size_t length, int prot, int flag,
int fd, off_t offset);
mmap 的前两个参数分别用于指定需要申请的空间起始地址和长度,如果起始地址设置为 0,那么 Linux 会自动挑选合适的起始地址。prot 和 flags 两个参数用于设置申请空间的权限(可读、可写、可执行)以及映射类型(文件映射、匿名空间)最后两个参数用于文件映射时指定的文件描述符和文件偏移。 mmap作用是向操作系统申请一段虚拟地址空间,这块虚拟地址空间可以映射到某个文件。当它不将地址空间映射到某个文件时,我们称这块空间为匿名空间,也就是

// 使用mmap实现简易malloc
void* malloc(size_t size) {
	void* ret = mmap(0, size, PROT_READ | PROT_WRITE, 
		MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
	if (ret == MAP_FAILED)
		return nullptr;
	return ret;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值