1.SGI标准中的两个空间配置器
std:allocator
不推荐使用,其实现主要是对::operator new
和operator delete
做简单包装而已std::alloc
将内存分配和对象内容构造分开
2.construct与destory
construct
destory
只接受一个指针的版本
destory
接受一对迭代器版本- 首先获取
value_type
- 萃取其特性
has_trivial_destructor
- 若为
__true_type
则什么都不做;否则循环调用第一个版本,即使用其析构函数
- 首先获取
- 综合概括
3.空间的配置与释放
3.1 双层配置器
- 第一层:直接使用
malloc
和free
- 第二层:若大于128Bytes,则使用第一级配置器;否则,采用内存池
memory pool
的方式
3.2 第一级配置器 __malloc_alloc_template
allocate
结构流程
reallocate
的过程与上述allocate
流程一致,只是最后换成oom_realloc
oom_malloc
的实现
3.2 第二级配置器__default_alloc_template
- 避免太多小额区块造成内存碎片,区块越小,造成的额外负担所占比例就越大
- 内存池 次层配置,每次配置一块大的内存,并维护在自由链表中,内存池同时也要负责将回收的区块加到
freelist
中管理 free_list
节点内容
unino obj{
union obj* free_list_link;
char client_data[1];
}
- 第一个字段:视为一个指针,指向相同形式的另一个obj
- 第二个字段:视为一个指针,指向实际区块
3.2.1 allocate
free_list
是一个指针数组,其中每一项存储一个指向区块开始的指针(obj*)- 首先根据内存需求量,找到最合适的一项(需求量需要用roundup作处理,使其是8的倍数),得到一个
obj** myfreelist
- 分配结果则为
result=*myfreelist
,调整free_list,*myfreelist=result->free_list_link;
- 若没有找到可用的free_list,则调用
refill
填充freelist
3.2.2 deallocate
- 首先判断区块大小,大于128则直接使用第一级配置器;小于128则找出对应的freelist 将其回收
3.2.3 refill
- 参数列表:size_t n 为一个对象的大小,n已经被上调至8的倍数
- nobjs=20 即每次refill会向内存池索要20个对象的空间,若空间不足,则会调整nobjs
- 过程如下:
- 调用chunk_alloc 取出20个对象的空间(可能少于20个)
char* chunk=chunk_alloc(n,nobjs)
- 将第一个直接分配給调用者,result=(obj*)chunk;
- 剩余的交给freelist管理
- 调用chunk_alloc 取出20个对象的空间(可能少于20个)
3.2.4 chunk_alloc
totalbytes=size*nobjs
- 若余量充足
- 余量>=size(可分配1个及以上)
- 不足分配一个,则使用malloc分配内存,补充内存池
- 要申请的内存量
bytes_to_get=2*total_bytes+ROUND_UP(heap_size>>4)
,即40个对象大小+n个附加量 - 将之前的残余量加到合适的free_list中
- 配置heap空间,补充内存池
- 若malloc失败,则往freelist大的方向查找未使用的区块,分配出一块,然后调用自己,修正nobjs
- 若malloc失败,且freelist里也没有剩余区块,尝试使用malloc::allocate,主要是寄希望于oom_malloc是否能够处理
- 最后调用自己修正nobjs
- 要申请的内存量