SGI STL考虑到小型内存区块的碎片问题,设计了双层级配置器,第一级配置直接使用malloc()和free();第二级配置器则视情况采用不同的策略,当配置区大于128bytes时,直接调用第一级配置器;当配置区块小于128bytes时,遍不借助第一级配置器,而使用一个memory pool来实现。究竟是使用第一级配置器还是第二级配置器,由一个宏定义来控制。SGI中默认使用第二级配置器。

第一级配置器实现的比较简单,调用malloc()申请内存,申请失败的时候,将抛出bad_alloc异常。下边我着重介绍下二级配置器的实现思路。

上边提到了第二级配置器视情况不同而采用不同的策略;其主要目的是避免太多小额区块造成内存的碎片。通常情况下,当配置区大于128bytes时,配置器视之为“足够大”而直接调用一级配置器,当配置区块小于128bytes时,就以内存池来管理,具体做法是:

sgi二级配置器会将任何小额区块的内存需求量上调至8的倍数,(例如需求是30bytes,则自动调整为32bytes),并且在它内部会维护16个free-list, 各自管理大小分别为8, 16, 24,…,128bytes的小额区块,这样当有小额内存配置需求时,直接从对应的free list中拔出对应大小的内存(8的倍数);当客户端归还内存时,将根据归还内存块的大小,将需要归还的内存插入到对应free list的最顶端。如下图:

图1

那么什么是free-list呢?

首先我们看下free-list的定义

上边free-list节点定义得非常巧妙,与普通链表节点采用struct不同,这里采用的是union;主要原因是由于为了维护free-list链表,每个节点需要额外的指针(指向下一个节点),这样就会造成一种内存浪费。为了避免这种负担,所以采用的union,根据union的特点,从第一个字段看,obj可以看作一个指针,指向链表中的下一个节点;从第二个字段看,obj也可以视为一个指针,不过是指向实际的内存区,如图1所示,这种一物两用的结果,就是不会为了维护链表所必须的指针而造成内存浪费。(因为stl容器是保存对象的,所以其自身信息当然要求是尽可能的少占用内存)。

下边我们根据一个图来讲下第二级空间配置器分配及归还内存区块的过程:

内存分配:

图2

如上,我们要申请96bytes的内存(由于其内部有自动调整机制,所以有可能89~95bytes的申请也会自动上调到96bytes), 首先确定需要在第几号free-list中获取,如图示是第11号free-list my_free_list,然后获取这个第一个元素(即第一块内存)的地址赋值给result,再调整my_free_list让其指向下一个区块。

 内存归还:

 图3
跟配置内存类似,同样是先寻找对应的free list,然后将要归还的内存块插入到对应free list的头部。
不过在内存配置的过程中,我们还需要处理这种情况:当对应free list没有可用区块时,就需要给对应的free list重新填充内存。如下图:

图4 
//传回一个大小为 n的对象,并且有时候会为适当的freelist增加节点.
//假设 n已经适当上调至 8的倍数。
template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
int nobjs = 20;
// 呼叫 chunk_alloc(),尝试取得 nobjs个区块做为 free list的新节点。
// 注意参数 nobjs是pass by reference。
char * chunk =chunk_alloc(n, nobjs);
obj * volatile * my_free_list;
obj * result;
obj * current_obj, * next_obj;
int i;
第 2 章空间配置器(allocator)
// 如果只获得一个区块,这个区块就拨给呼叫者用,free list无新节点。
if (1 == nobjs) return(chunk);
// 否则准备调整 free list,纳入新节点。
my_free_list = free_list + FREELIST_INDEX(n);
// 以下在 chunk空间内建立freelist
result = (obj *)chunk; //这一块准备传回给客端
// 以下导引 free list指向新配置的空间(取自记忆池)
*my_free_list = next_obj = (obj *)(chunk + n);
// 以下将 free list 的各节点串接起来。
for (i = 1; ; i++) {//从 1 开始,因为第 0 个将传回给客端
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if (nobjs - 1 == i) {
current_obj -> free_list_link = 0;
break;
} else {
current_obj -> free_list_link = next_obj;
}
}
return(result);
}

refill()函数完成的主要功能是:根据所需要申请的区块的大小n,调用chunk_alloc(n, nobjs); 默认申请nobjs个区块(默认为20,又可能不足20,nobjs是引用传递);如果申请的区块只有一个,那么直接返回,free list仍旧无可用区块,如果大于1,那么将第一个chunk块作为返回值,其余的chunk按照n划分为free list的节点,并将其串接到free list中区。最后free list头节点会指向到新分配的chunk。

综上,我便将stl二级空间配置的空间的配置,回收,以及重新填充大小详细介绍了一遍,下篇将继续介绍内存池的设计。

stl第二级空间配置器详解(1)的更多相关文章

  1. STL源代码分析--第二级空间配置器

    本文解说SGI STL空间配置器的第二级配置器. 相比第一级配置器,第二级配置器多了一些机制,避免小额区块造成内存的碎片.不不过碎片的问题,配置时的额外负担也是一个大问题.由于区块越小,额外负担所占的 ...

  2. stl中的空间配置器

    一般我们习惯的c++内存配置如下 class Foo { ... }; Foo* pf = new Foo; delete pf; 这里的new实际上分为两部分执行.首先是先用::operator n ...

  3. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  4. C++ STL学习之 空间配置器(allocator)

    众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间 ...

  5. STL——模拟实现空间配置器

    目录 问题 SGI版本空间配置器-std::alloc 一级空间配置器 二级空间配置器 Refill.chunkAlloc函数 最后,配置器封装的simple_alloc接口 问题 我们在日常编写C+ ...

  6. STL源码剖析(空间配置器)

    前言 在STL中,容器的定义中都带一个模板参数,如vector template <class T, class Alloc = alloc> class vector {...} 其中第 ...

  7. STL之空间配置器

    在前面很多随笔里都有提到new对象是先分配内存然后初始化对象,主要是对operator new和placement new的使用 在SGI STL中内存的分配和初始化是分开的,分配内存是使用类模板,模 ...

  8. stl空间配置器alloc

    new运算包含两阶段操作: 1) 调用::operator new分配内存     2) 调用构造函数构造对象内容 delete运算包含两阶段操作: 1)调用析构函数将对象析构    2)调用::op ...

  9. [stl] SGI STL的空间配置器

    第一级空间配置器 第一级配置以malloc(), free(), realloc()等c函数执行实际的内存配置,释放.重配置操作,并实现出类似c++ new handler的机制.它不能直接使用c++ ...

随机推荐

  1. 【CSAPP笔记】7. 汇编语言——过程调用

    一个过程调用包括将数据(以参数和返回值的形式)与控制从代码的一部分传递到另一部分.除此之外,在进入时为过程的局部变量分配空间,在退出的时候释放这些空间.数据传递.局部变量的分配和释放通过操纵程序栈来实 ...

  2. IT行业的个人见解

    IT这个行业是近代历史上的新新行业,它的就业前景是非常的好的,就业率高,但是这个行业的需求人才精英不是那些半桶水的所谓IT男.我现在学习的是计算机专业中的软件工程目标是成为一名合格的软件工程师,软件工 ...

  3. SOAP 缓存问题

    今天在进行soap调用老是出错,去其他人的机器上试下,就好了,下面是从网上找到的原因 一开始不知道还有SOAP缓存.因为类文件改变了,重新生成了WSDL文件,测试运行,竟然不能通过.给我的第一感觉是W ...

  4. 一键轻松查看apk包名和Main Activity

    环境 Windows系统(我的是Win10 64位) Python3(我的是3.6.1) 已安装Git 安装 pip install git+https://github.com/codeskyblu ...

  5. 转:关于python文件操作大全

    转自:http://www.cnblogs.com/rollenholt/archive/2012/04/23/2466179.html python中对文件.文件夹(文件操作函数)的操作需要涉及到o ...

  6. PHP中文字符gbk编码与UTF-8编码的转换

    通常PHP中上传文件,如果文件名称有中文字符,上传之后的名称是无法写入到本地的,因为上传来的编码格式一般是UTF-8的格式,这种格式是无法给文件命名并且存储到操作系统磁盘.在写入之前需要将其转换为gb ...

  7. BZOJ3688 折线统计 【dp + BIT】

    题目链接 BZOJ3688 题解 将点排序 设\(f[i][j][0|1]\)表示以第\(i\)点结尾,有\(j\)段,最后一段上升或者下降的方案数 以上升为例 \[f[i][j][0] = \sum ...

  8. java解数独

    先输入要解的数独,采用多维数组来保存其中的值,未填数字的地方,初始化为0,然后采用递归的方法来解数独. 直接上代码: /** * * @author walker * */ public class ...

  9. Java之Java程序与虚拟机

    Java为什么要在虚拟机中运行 简单的来说,Java作为一门高级程序语言,语法复杂,抽象度高,不能直接翻译为机器码在机器上运行,所以设计者就设计了虚拟机,通过编译器将Java程序转换成虚拟机所能识别的 ...

  10. python之旅:面向对象之多态、多态性

    一 多态 多态指的是一类事物有多种形态 eg:动物有多种形态:猫,狗,猪 class Animal: #动物类 def eat(self): #吃 pass def drink(self): #喝 p ...