STL(一)空间配置器的实现

空间配置器内存分配和释放第一层配置器第二层配置器内存池分配回收总结内存分配和释放当我们 new 一个对象的时候,包含两个操作,首先 operator_new 分配内存,再调用构造函数构造对象内容但我们 delete 一个对象的时候,同样先调用析构函数,再调用 operator_delete 释放内存STL 将这个过程薄薄的包装了一下,实际上没优化配置器定义于 中, 中又包含 <stl_alloc.h> <stl_construct.h>内存配置由 alloc::all
摘要由CSDN通过智能技术生成

开源地址:Gitee :zhujilun : 完全注释版 Tiny STL


内存分配和释放

当我们 new 一个对象的时候,包含两个操作,首先 operator_new 分配内存,再调用构造函数构造对象内容
但我们 delete 一个对象的时候,同样先调用析构函数,再调用 operator_delete 释放内存

STL 将这个过程薄薄的包装了一下,实际上没优化

配置器定义于 中, 中又包含 <stl_alloc.h> <stl_construct.h>

内存配置由 alloc::allocate() 负责,内存释放由 alloc::deallocate() 负责
构造对象由 construct::construct() 负责,析构对象由 construct::destroy() 负责

内存分配中有几个问题:

1.可能会内存不足
2.小块内存会导致碎片
3.频繁申请/释放小块内存的性能问题

为了解决这些问题,STL 设计了双层配置器

第一层配置器直接使用 malloc()、free(),当配置区块超过128 bytes,认为足够大,直接用第一层配置器

第二层配置器使用内存池和自由链表

第一层配置器

第一层配置器{
   
	直接 malloc(n) 申请内存
	if 内存够{
   
		直接申请成功
		return
	}
	else{
   
		调用内存不足处理函数oom_malloc(n)
		if 内存不足时,释放内存的句柄 handler == 0{
   
			throw std::bad_alloc 没设置的话系统也没法,没有内存了,也没法释放内存,只能给抛个异常
		}
		else{
   
			while ret == 0 {
   
				系统释放一块内存,释放出来了就有 ret = 1
				否则一直循环
			}
			return
		}
	}
}

这样的malloc和free看似很方便,但正因为它的方便,通用,因此性能不高,在它的实现中还要配合操作系统才能完全完成

malloc(n){
   
	不断搜索空闲内存块
	if 找到了 {
   
		return 把这块分配出去
	} else {
   
		brk:扩大堆区,获得更多的空闲内存,此时转入内核态
		—————————————————————————————————————————
		虚拟内存系统开始工作                      内
		额外扩大的这一部分仅仅是虚拟内存            核
		并没有真的分配物理内存                    态
		—————————————————————————————————————————
		return 找到一块合适的空闲内存
	}
}

第二层配置器

内存池

首先介绍一下内存池

在内核中,有的地方要内存时,不能出现分配不了的情况,为了确保分配,与效率问题,需要内存池作为后备缓存,尽力保持出一个空间紧急使用

在真正使用内存前,先申请出一定数量的大小相等的(一大块)内存块,当有内存需求时,从内存块中分出几个,如果这些还不够,再申请新的内存

分配

首先有一个free_lists[16],每一位上记录大小为8、16、24、… 、128的区块数

并维护16个free_list,各自管理各自的区块

if free_list 中有空余内存{
   
	for{
   
		找到free_list[i]
		break;
	}
	先把申请的字节数修改为8的倍数
	return 该位置链表中第一个元素
	头指针后移
}
else{
   
	if 内存池 !={
   
		if 内存池大小 > 申请的内存 * 8{
   
			分配相应的内存
			其中一个给用户return
			其他的7个挂在free_list上
		} else if 申请的内存 * 8 > 内存池大小 && 内存池大小 > 申请的内存 {
   
			先凑合分配这几个
			其中一个给用户return
			剩下的挂链表
		} else {
     //内存池不够
			if malloc(申请的一大块内存放进内存池) 成功{
   
				一个给用户
				剩下的挂链表
				剩下的放内存池
			}
			else {
   
				调用第一层配置器
			}
		}
	}
}

回收

当申请释放一块内存时,这个内存被插入到对应的free_list中

总结

以上仅仅是STL的做法,具有一定的通用性,因此性能不会太好,在实际场景中肯定还是要自己写内存池的

代码实现

union obj {
             //避免内存浪费的union
		union obj *next; //指向下一个区块
		char client[1];  //储存本块内存的首地址
	};

                
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱骥伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值