STL_空间配置器(allocators)
SGI STL中的两级空间分配器
第一级 __malloc_alloc_template
template <int __inst>
class __malloc_alloc_template {
private:
static void* _S_oom_malloc(size_t);/*函数指针处理out of memory 情况*/
static void* _S_oom_realloc(void*, size_t);
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
static void (* __malloc_alloc_oom_handler)();
#endif
public:
static void* allocate(size_t __n)
{
void* __result = malloc(__n); /*直接调用malloc()*/
if (0 == __result) __result = _S_oom_malloc(__n); /*处理OOM方式都相似,只列出allocate情况*/
return __result;
}
static void deallocate(void* __p, size_t /* __n */)
{
free(__p);
}
static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)
{
void* __result = realloc(__p, __new_sz);
if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);
return __result;
}
// 仿set_new_handler(只用于::operator new配置内存方式,malloc不能使用)
// typedef void(*pf)() PF
// PF __set_malloc_handler(void (*__f)())
// __set_malloc_handler接收 void(*)()函数指针
// 同时返回 void(*)()函数指针
static void (* __set_malloc_handler(void (*__f)()))()
{
void (* __old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = __f;
return(__old);
}
};
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int __inst>
void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0; /*初始化位空,需要用户指定*/
#endif
template <int __inst>
void* __malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n)
{
void (* __my_malloc_handler)();
void* __result;
for (;;) { /*使用设定的handler处理,重复申请*/
__my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; } /*如果没有设定直接抛出异常*/
(*__my_malloc_handler)();
__result = malloc(__n);
if (__result) return(__result);/*如果成功则返回*/
}
}
第一级非常简单,只是把malloc,free,realloc包装了一下,并提供一个类似set_new_handler的方法。用户需要自己设定handler,否则使用默认的throw std::bad_alloc()方式。
第二级 __default_alloc_template
第二级主要避免小额区块造成的内存碎片,以及频繁申请带来的负担。SGI的二级做法是如果区块大于128字节,移交第一级,否则以内存池管理,每次申请一块大内存,通过空闲链表(free-lists)分配和回收内存,二级配置会将小额区块的请求调到8的倍数。并维护16个free-lists各自管理大小为8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128的区块。
union _Obj {
union _Obj* _M_free_list_link;
char _M_client_data[1]; /*The client sees this.*/
};
使用union结构体_Obj,第一个字段可视为指针,指向同一个free-list的下一个块,在freelist中用作链表;第二个字段可视为指向这一区块的指针,当申请到这一块内存后,p = *_Obj指向可用的内存。
enum {_ALIGN = 8};
enum {_MAX_BYTES = 128};
enum {_NFREELISTS = 16};
static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; //16个freelist
static size_t _S_round_up(size_t __bytes) {//将 size 上调为8的倍数
return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1));
}
static size_t _S_freelist_index(size_t __bytes) { // 返回size对应的freelist下标
return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);
}
/*allocate -- 用户分配空间*/
/* __n must be > 0 */
static void* allocate(size_t __n)
{
void* __ret = 0;
if (__n > (size_t) _MAX_BYTES) { //大于128,调用第一级
__ret = malloc_alloc::allocate(__n);
}
else {
_Obj* __STL_VOLATILE* __my_free_list
= _S_free_list + _S_freelist_index(__n);//得到对应freelist下标
// Acquire the lock here with a constructor call.
// This ensures that it is released in exit or during stack
// unwinding.
#ifndef _NOTHREADS
/*REFERENCED*/
_Lock __lock_instance; //多线程相关
#endif
_Obj* __RESTRICT __result = *__my_free_list;
if (__result == 0)//初次初始化||空间无剩余
__ret = _S_refill(_S_round_up(__n));//重新申请
else {
*__my_free_list = __result -> _M_free_list_link;//更新freelist列表,最后一块的_M_free_list_link设为0
__ret = __result;//返回内存地址
}
}
return __ret;
};
/*_S_refill -- 填充freelist*/
template <bool __threads, int __inst>
void*
__default_alloc_template<__threads, __inst>::_S_refill(size_t __n)
{
int __nobjs = 20; //分配__nobjs个区块
char* __chunk = _S_chunk_alloc(__n, __nobjs);//__nobjs 为value-result参数
_Obj* __STL_VOLATILE* __my_free_list;
_Obj* __result;
_Obj* __current_obj;
_Obj* __next_obj;
int __i;
if (1 == __nobjs) return(__chunk);//只有一块,直接返回
__my_free_list = _S_free_list + _S_freelist_index(__n);
/* 使用剩余内存构建该下标的freelist */
__result = (_Obj*)__chunk;
*__my_free_list = __next_obj = (_Obj*)(__chunk + __n);
for (__i = 1; ; __i++) {
__current_obj = __next_obj;
__next_obj = (_Obj*)((char*)__next_obj + __n);
if (__nobjs - 1 == __i) {
__current_obj -> _M_free_list_link = 0;//最后一块设为0
break;
} else {
__current_obj -> _M_free_list_link = __next_obj;
}
}
return(__result);
}
/*_S_chunk_alloc -- 从内存池取一定数量区块*/
template <bool __threads, int __inst>
char*
__default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size,
int& __nobjs)
{
char* __result;
size_t __total_bytes = __size * __nobjs;
size_t __bytes_left = _S_end_free - _S_start_free;/*内存池剩余空间*/
if (__bytes_left >= __total_bytes) {//足够分配__nobjs个区块
__result = _S_start_free;
_S_start_free += __total_bytes;//分配好后,剩余的留给内存池,用作下次分配
return(__result);
} else if (__bytes_left >= __size) {//不够__nobjs块,剩下的全都分配来,更新__nobjs
__nobjs = (int)(__bytes_left/__size);
__total_bytes = __size * __nobjs;
__result = _S_start_free;
_S_start_free += __total_bytes;
return(__result);
} else {//否则重新申请
size_t __bytes_to_get =
2 * __total_bytes + _S_round_up(_S_heap_size >> 4);//申请两倍 + heap_size/16
// 试试剩下的(必定为8的倍数)够不够小尺寸freelist使用
if (__bytes_left > 0) {//将内存池中区块交给相应的free_list
_Obj* __STL_VOLATILE* __my_free_list =
_S_free_list + _S_freelist_index(__bytes_left);
((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
*__my_free_list = (_Obj*)_S_start_free;
}
_S_start_free = (char*)malloc(__bytes_to_get);
if (0 == _S_start_free) {//malloc()失败,不会尝试小于__bytes_to_get的请求,出于效率以及减少内存碎片
size_t __i;
_Obj* __STL_VOLATILE* __my_free_list;
_Obj* __p;
// 从已经分配到的区块中搜寻。
for (__i = __size;
__i <= (size_t) _MAX_BYTES;
__i += (size_t) _ALIGN) {
__my_free_list = _S_free_list + _S_freelist_index(__i);
__p = *__my_free_list;
if (0 != __p) {
*__my_free_list = __p -> _M_free_list_link;
_S_start_free = (char*)__p;
_S_end_free = _S_start_free + __i;//取出一块
return(_S_chunk_alloc(__size, __nobjs));//重新分配调整,修正__nobjs
}
}
_S_end_free = 0; // 无论如何申请不到,调用第一级,试试OOM handler有没有用
_S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);
}
_S_heap_size += __bytes_to_get;
_S_end_free = _S_start_free + __bytes_to_get;
return(_S_chunk_alloc(__size, __nobjs));//修正__nobjs,将多余内存归还内存池
}
}
/*deallocate() -- 用户释放空间*/
static void deallocate(void* __p, size_t __n)
{
if (__n > (size_t) _MAX_BYTES)
malloc_alloc::deallocate(__p, __n);调用第一级
else {
_Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n);
_Obj* __q = (_Obj*)__p;
// acquire lock
#ifndef _NOTHREADS
/*REFERENCED*/
_Lock __lock_instance;
#endif /* _NOTHREADS */
__q -> _M_free_list_link = *__my_free_list;
*__my_free_list = __q;//将 __q区间插入对应freelist头部
// lock is released here
}
}
/*reallocate -- 重新分配空间*/
template <bool threads, int inst>
void*
__default_alloc_template<threads, inst>::reallocate(void* __p,
size_t __old_sz,
size_t __new_sz)
{
void* __result;
size_t __copy_sz;
if (__old_sz > (size_t) _MAX_BYTES && __new_sz > (size_t) _MAX_BYTES) {
return(realloc(__p, __new_sz));//调用第一级
}
if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
__result = allocate(__new_sz);//申请
__copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
memcpy(__result, __p, __copy_sz);//拷贝
deallocate(__p, __old_sz);//释放
return(__result);
}
空间初始化
内存分配完毕后,STL定义五个全局函数用于未初始化的空间。
construct && destroy() – 用于构造,析构对象
#include <new.h> //使用placement new
template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {
new ((void*) __p) _T1(__value);// T1::T1(__value)
}
template <class _T1>
inline void _Construct(_T1* __p) {
new ((void*) __p) _T1();
}
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
__pointer->~_Tp();
}
//接收迭代器,找出元素类别,根据__type_traits<>采取适当措施
template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {
__destroy(__first, __last, __VALUE_TYPE(__first));
}
template <class _ForwardIterator>
void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)//non-trivial destructor
{
for ( ; __first != __last; ++__first)
destroy(&*__first);
}
template <class _ForwardIterator>
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}//trivial destructor,不采取操作
construct()通过指针p,可选的初值value,使用placement new运算子在对象构造在p所指的空间上。
destroy()有两个版本,第一个接受一个指针;第二个接收迭代器,将[first,last)范围内的所有对象析构,首先使用 value_type获得对象类型,在进行trivial destructor的判定,如果析构函数是不重要的,destroy()最终不调用任何操作,否则才调用析构函数。
uninitialized_fill_n, uninitialized_fill, unitialized_copy
/*__uninitialized_fill_n : first:初始化空间起始,n:空间大小,x:初值*/
template <class _ForwardIter, class _Size, class _Tp, class _Tp1>
inline _ForwardIter
__uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x, _Tp1*)
{
typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD;
return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD());
}
/*判断Tp1是否为POD(plain old data)类型,简单来说POD类型支持memcpy等类似的函数直接拷贝对象的二进制值。*/
//是POD类型,fill_n通过赋值进行填充
template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter
__uninitialized_fill_n_aux(_ForwardIter __first,
_Size __n,
const _Tp& __x,
__true_type)
{
return fill_n(__first, __n, __x);
}
// 非POD,调用Construct。
template <class _ForwardIter, class _Size, class _Tp>
_ForwardIter
__uninitialized_fill_n_aux(_ForwardIter __first,
_Size __n,
const _Tp& __x,
__false_type)
{
_ForwardIter __cur = __first;
__STL_TRY {
for ( ; __n > 0; --__n, ++__cur)
_Construct(&*__cur, __x);
return __cur;
}
__STL_UNWIND(_Destroy(__first, __cur));//一旦发生异常全部析构
}
这三个函数都要求"commit or rollback"语义,要么产生所有元素,要么不产生任何元素。上面异常处理模块保证了这一语义。
/*uninitlized_cpoy,first:起始位置,last:结束位置,result:初始化空间起始*/
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
uninitialized_copy(_InputIter __first,
_InputIter __last,
_ForwardIter __result)
{
return __uninitialized_copy(__first, __last, __result, __VALUE_TYPE(__result));
}
template <class _InputIter, class _ForwardIter, class _Tp>
inline _ForwardIter
__uninitialized_copy(_InputIter __first,
_InputIter __last,
_ForwardIter __result,
_Tp*)
{
typedef typename __type_traits<_Tp>::is_POD_type _Is_POD;
return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());
}
//POD类型,调用copy,填充赋值
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
_ForwardIter __result,
__true_type)
{
return copy(__first, __last, __result);
}
//非POD类型
template <class _InputIter, class _ForwardIter>
_ForwardIter
__uninitialized_copy_aux(_InputIter __first,
_InputIter __last,
_ForwardIter __result,
__false_type)
{
_ForwardIter __cur = __result;
__STL_TRY {
for ( ; __first != __last; ++__first, ++__cur)
_Construct(&*__cur, *__first);
return __cur;
}
__STL_UNWIND(_Destroy(__result, __cur));
}
对于char* 和 wchar_t*两种类型,uninitialized_copy直接采用memmove直接移动内容
//uninitialized_copy: first:初始化空间起始,last:初始化空间结束(前闭后开),x:初值
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
uninitialized_copy(_InputIter __first,
_InputIter __last,
_ForwardIter __result)
{
return __uninitialized_copy(__first, __last, __result,
__VALUE_TYPE(__result));
}
//POD类型
template <class _ForwardIter, class _Tp>
inline void
__uninitialized_fill_aux(_ForwardIter __first,
_ForwardIter __last,
const _Tp& __x,
__true_type)
{
fill(__first, __last, __x);
}
//非POD
template <class _ForwardIter, class _Tp>
void
__uninitialized_fill_aux(_ForwardIter __first,
_ForwardIter __last,
const _Tp& __x,
__false_type)
{
_ForwardIter __cur = __first;
__STL_TRY {
for ( ; __cur != __last; ++__cur)
_Construct(&*__cur, __x);
}
__STL_UNWIND(_Destroy(__first, __cur));
}
三个函数实现了不同的功能,它们都用于未初始化的空间。