//---------------------------15/04/05----------------------------
/*
空间配置器概述:
1:new操作包含两个阶段操作
1>调用::operator new配置内存(底层使用malloc来申请内存)。
2>调用函数的构造函数,构造对象内容。
delte和new一样,先调用析构函数,再调用::operator delete释放内存。
2:为了效率,stl把两个阶段分开来。
1>内存配置操作: alloc::allocate();
2>内存释放操作: alloc::deallocate();
3>对象构造操作: ::construct();
4>对象析构操作: ::destory();
3:内存配置器的整体:
1><stl_construct.h> : 这里定义了全局函数construct()和的destroy()。
2><stl_alloc.h> : 定义了一二级配置器。
3><stl_uninitialized.h> : 定义了一些全局函数,用来填充或复制大块内存数据。
un_initialized_copy(), un_initialized_fill(), un_initialized_fill_n()
这些函数对效率考虑得面面俱到:最差的情况下会调用construct(),最佳的情况下会
使用c的标准函数memmove()直接进行内存数据的移动。
*/
//construct() 和 destroy()
template<class T1,
class T2>
inline
void construct(T1* p,
const T2& value)
{
new (p) T1(value);
}
template<class T>
inline
void destroy(T* pointer)
{
pointer->~T();
}
template<class ForwardIterator>
inline
void destroy(ForwardIterator first, ForwardIterator last)
{
__destroy(first, last, value_type(first));
}
template<class ForwardIterator,
class T>
inline
void __destroy(ForwardIterator first, ForwardIterator last, T*)
{
typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first, last, trivial_destructor());
}
template<class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
{
for(; first < last; ++first)
destroy(&*first);
}
template<class ForwardIterator>
inline
void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}
inline
void destroy(char*,
char*) {}
inline void destroy(wchar_t*,
wchar_t*) {}
//alloc
template<class T,
class Alloc>
class simple_alloc
{
public:
static T* allocate(size_t n)
{
== n ?
: (T*) Alloc::allocate(n *
sizeof(T));
}
static T* allocate(void)
{
return (T*) Alloc::allocate(sizeof(T));
}
static void deallocate(T *p, size_t n)
{
!= n)
Alloc::deallocate(p, n *
sizeof(T));
}
static void deallocate(T *p)
{
Alloc::deallocate(p,
sizeof(T));
}
};
//第一级配置
template<int inst>
class __malloc_alloc_template
{
private:
static void* oom_malloc(size_t);
static void* oom_realloc(void *, size_t);
static void (* __malloc_alloc_oom_handler)();
public:
//直接调用malloc分配内存,失败就调用oom_malloc,这个函数会不断申请分配,
//并不断调用处理函数,如果没有处理函数,就抛出错误。
static void* allocate(size_t n)
{
void *result = malloc(n);
== result)
result == oom_malloc(n);
return result;
}
static void deallocate(void *p, size_t)
{
free(p);
}
static void* reallocate(void *p, size_t, size_t new_sz)
{
void *result = realloc(p, new_sz);
== result)
result = oom_realloc(p, new_sz);
return result;
}
static void (* set_malloc_handle(void (*f)()))()
{
void ( *old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return(old);
}
};
template<int inst>
void ( *__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() =
;
template<int inst>
void* __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
void ( *my_malloc_handler)();
void *result;
for(; ;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
== my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = malloc(n);
if(result)
return (result);
}
}
template<int inst>
void* __malloc_alloc_oom_handler<int>::oom_realloc(void *p, size_t n)
{
void ( *my_malloc_handler());
void *result;
for(; ;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
== my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
(*my_malloc_handler)();
result = realloc(p, n);
if(result)
return (result);
}
}
> malloc_alloc;
//第二级配置器
//使用union节省空间
union obj
{
union obj * free_list_link;
];
};
enum { __ALIGN =
};
enum { __MAX_BYTES =
};
enum { __NFREELISTS = __MAX_BYTES / __ALIGN};
template<bool threads,
int inst>
class __default_alloc_template
{
private:
//这里就是加7再对8取模
这样写的公式扩展性比较小, 也就是__ALIGN必须取2的倍数,
//不然这公式就不是取模操作了。
static size_t ROUND_UP(size_t bytes)
{
) & ~(__ALIGN - ));
}
union obj
{
union obj *free_list_link;
];
};
static obj * volatile free_list[__NFREELISTS];
static size_t FREELIST_INDEX(size_t bytes)
{
) / __ALIGN - ));
}
static void* refill(size_t n);
static char *chunk_alloc(size_t size,
int &nobjs);
static char *start_free;
static char *end_free;
static size_t heap_size;
public:
static void* allocate(size_t n)
{
obj *
volatile * my_free_list;
obj * result;
if(n > (size_t)__MAX_BYTES)
return (malloc_alloc::allocate(n));
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
)
{
void *r = refill(ROUND_UP(n));
return r;
}
*my_free_list = result->free_list_link;
return (result);
}
//如果比最大大小大,就交给第一级配置,否则收回到链表中
static void deallocate(void *p, size_t n)
{
obj *q = (obj*)p;
obj *
volatile * my_free_list;
if(n > (size_t)__MAX_BYTES)
{
malloc_alloc::deallocate(p, n);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
q->free_list_link = *my_free_list;
*my_free_list = q;
}
static void* reallocate(void *p, size_t old_sz, size_t new_sz);
};
template<bool threads,
int inst>
char *__default_alloc_template<threads, inst>::start_free =
;
template<bool threads,
int inst>
char *__default_alloc_template<threads, inst>::end_free =
;
template<bool threads,
int inst>
size_t *__default_alloc_template<threads, inst>::heap_size =
;
template<bool threads,
int inst>
__default_alloc_template<threads, inst>::obj *volatile
__default_alloc_template<threads, inst>::free_list[__NFREELISTS] =
{,
, , , , ,
, , , , ,
, , , , };
template<bool threads,
int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
//20个节点
;
//申请20个节点,会修改nobjs的值,也就是申请到多少个节点
char *chunk = chunk_alloc(n, nobjs);
obj *
volatile * my_free_list;
obj *result;
obj *current_obj, *next_obj;
int i;
//如果只申请到一个节点,直接返回
== nobjs)
return (chunk);
//找到n大小节点的位置
my_free_list = free_list + FREELIST_INDEX(n);
//第一个节点是用来返回的,不用存入链表中
result = (obj*)chunk;
//链表的第一个节点就是下一个节点
*my_free_list = next_obj = (obj*)(chunk + n);
; ; i++)
{
//当前节点是下一个节点
current_obj = next_obj;
//下一个节点是下下个节点
next_obj = (obj*)((char*)next_obj + n);
//如果是最后的节点了,就设置下个节点为0,并返回,否则好设置下一个节点
== i)
{
current_obj->free_list_link =
;
break;
}
else
{
current_obj->free_list_link = next_obj;
}
}
//把申请到的第一个节点返回
return (result);
}
template<bool threads,
int inst>
char* __default_alloc_template<threads, inst>::
chunk_alloc(size_t size,
int& nobjs)
{
char *result;
//需要的总大小(bytes)
size_t total_bytes = size * nobjs;
//内存池中剩余的大小
size_t bytes_left = end_free - start_free;
//如果剩余的大小大于总大小,直接返回就行了
if(bytes_left >= total_bytes)
{
result = start_free;
start_free += total_bytes;
return (result);
}
//如果剩下的大小大于一个size,
就返回最大的内存大小
else if(bytes_left >= size)
{
nobjs = bytes_left / size;
total_bytes = size * nobjs;
result = start_free;
start_free += total_bytes;
return (result);
}
//一个都没有
else
{
//算出需要的内存大小,2倍的需求量+现有大小的1/16(需要调整)。
size_t bytes_to_get =
* total_bytes + ROUND_UP(heap_size >> );
//先把内存池中剩余的空间中的内存取出放入链表中
)
{
obj *
volatile * my_free_list =
free_list + FREELIST_INDEX(bytes_left);
((obj*)start_free)->free_list_link = *my_free_list;
*my_free_list = (obj*)start_free;
}
//申请内存
start_free = (char*)malloc(bytes_to_get);
== start_free)
{
//无法正常申请内存
int i;
obj *
volatile * my_free_list, *p;
//尝试拆分大节点
for(i = size; i <= __MAX_BYTES; i += __ALIGN)
{
//找到比要申请的内存大一点的节点,可以把他拆分掉
my_free_list = free_list + FREELIST_INDEX(i);
//让p等于这个链表的第一个节点
p = *my_free_list;
!= p)
{
//如果有节点,就把这个节点放入内存池中
*my_free_list = p->free_list_link;
start_free = (char*)p;
end_free = start_free + i;
return (chunk_alloc(size, nobjs));
}
}
//如果找不到大的节点,只能调用第一级配置,调用客户设置的处理函数了。
end_free =
;
start_free = (char*)malloc_alloc::allocate(bytes_to_get);
}
//内存池大小调整
heap_size += bytes_to_get;
end_free = start_free + bytes_to_get;
return (chunk_alloc(size, nobjs));
}
}