项目-STL空间配置器

这篇博客主要讲一下SGI-STL中的空间配置器的工作流程。

一、项目背景
  1. 小块内存带来的内存碎片问题(外碎片问题)
  2. 小块内存频繁申请释放带来的性能问题
二、空间配置器的思想

对于我们来说,对new和delete很熟悉,这两个函数可以分别完成内存的申请和释放,和c里面的malloc和free如出一辙。
Std::alloc的主要思想是:
(1)定义一个空间大小阈值,128bytes;
(2)如果申请的空间大于128bytes,那么就调用第一级空间适配器来完成分配工作;
(3)如果小于128bytes,那么就调用第二级空间适配器来完成。

一级空间配置器

一级空间配置器是以malloc(),free(),realloc()等C函数执行实际的内存配置、释放、重配置操作,并实现了C++的set_new_handler()函数。
它的内部设计实际就是为了压榨剩余的内存,达到内存的高效运用。所以一级空间配置器内部其实就是malloc和free的封装,然后尽量的开辟出用户想要的内存空间。
具体步骤如下:
这里写图片描述
一级空间配置器

二级空间配置器

二级空间配置器使用内存池+自由链表的形式避免了小块内存带来的碎片化,提高了分配的效率,提高了利用率。
见下图:
这里写图片描述
二级空间配置器

项目流程
  1. List.h、Vector.h是模仿STL容器中的两个list和vector的接口
  2. Allocate.h里面定义了内存池即空间配置器的两级实现
  3. Construct.h里面主要实现了对象的构造与析构接口
  4. Iterator.h里面有五种迭代器的定义、迭代器萃取、反向迭代器定义、迭代器型别萃取以及两个非常有用的函数 Distance、Advance
  5. TypeTraits.h定义了迭代器所指节点的值类型萃取,是否是POD类型
  6. Uninitialized.h里面是主要是一些拷贝、填充类的函数
  7. Main.cpp是测试文件,用来测试两个容器的接口和内存池实现正确与否
空间配置器的问题
  1. 在空间配置器中所有的函数和变量都是静态的,所以他们在程序结束的时候才会被释放发。二级空间配置器中没有将申请的内存还给操作系统,只是将他们挂在自由链表上。所以说只有当你的程序结束了之后才会将开辟的内存还给操作系统。

  2. 由于它没有将内存还给操作系统,所以就会出现二种极端的情况。
    2.1. 假如我不断的开辟小块内存,最后将整个heap上的内存都挂在了自由链表上,但是都没有用这些空间,再想要开辟一个大块内存的话会开辟失败。
    2.2. 再比如我不断的开辟char,最后将整个heap内存全挂在了自由链表的第一个结点的后面,这时候我再想开辟一个16个字节的内存,也会失败。
    解决方法:
    我想的是,针对2.1我们可以引入释放二级空间配置器的方法,但是这个释放比较麻烦。针对2.2我们可以合并自由链表上的连续的小的内存块。

  3. 为什么引入复杂的两级空间配置器?
    (1). 频繁使用malloc,free开辟释放小块内存带来的性能效率的低下
    (2). 内存碎片问题,导致不连续内存不可用的浪费

  4. 为什么所有成员函数都是静态的?
    是为了在外面通过作用域就可以调用,而不需要构造对象

  5. ROUNT_UP的实现原理是什么?
static size_t ROUND_UP(size_t bytes)//作用是将非8倍数的整数上调到8的倍数。
{
       return (((bytes)+__ALIGN - 1) &~(__ALIGN - 1));
}

round_up实现原理:
以 bytes = 30为例:
a. (30 + 7) = 37, 可以知道30的round_up为32, 给32加(8-1)的目的是让其(一定)大于32
b. 这样的话,以十进制形式,37肯定可以表达为如下的形式:(x*8 + y), 并且可以肯定这个y的值小于8,上述37表达形式为:(32 + 5)
c. 根据上述b步骤的形式,我们很自然的明白, 只要将 ((bytes) + 8-1) 转换为(x*8 + y)的形式后,然后再将y的值减去就达到目的了
d. 总结上述思路,我们要做事情有两个,一是将 ((bytes) + 8-1) 转换为 (x*8 + y)的形式; 二是将(x*8 + y)中的y值清零
e. 在十进制下,要完成上述任务,比较困难,而在二进制下,就非常好办
f. 首先,将 ((bytes) + 8-1) 转换为(x*8 + y), 只要将 ((bytes) + 8-1)的值转为二进制,如以37为例,其二进制为: 00100101,这样写你可能看得还不是很直观,这样写 (00100) (101),这样就可以发现,第一个小括号里面的值就为(x*8), 第二个小括号里面的值就为(y);接下来,我们的目的就很简单的, 将第二个小括号里面的所有位置为0即可, 参考上述网页中的规则“非运算和与运算结合,可以确保将指定位 清0, 故 & ~(__ALIGN - 1)的目的就是将第二个小括号中的位清0。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值