STL源码剖析:Allocator
SGI标准的空间适配器
SGI标准的适配器名为 std::allocator。该空间适配器只是对c++的::operator new 和 ::operator delete做了一层浅封装,并且由于封装的缘故反而降低了效率。
template <class T>
inline T* allocate(ptrdiff_t size, T*) {
set_new_handler(0);
T* tmp = (T*)(::operator new (size_t)(size * sizeof(T)));
if (tmp == 0) {
cerr << "out of memory" << endl;
exit(1);
}
return tmp;
}
template <class T>
inline void deallocate(T* buffer) {
::operator delete(buffer);
}
SGI特殊的空间适配器
SGI特殊的空间适配器称为 std::alloc
在该适配器中,将new和delete的操作细分为四个操作
- 内存配置由alloc::allocate()负责
- 内存释放由alloc::deallocate()负责
- 对象的构造操作由::construct()负责
- 对象的析构操作由::destroy()负责
构造和析构的基本工具:construct()和destroy()
构造函数construct()通过placement new 在已经分配的内存上调用对象的构造函数
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();
}
//第二个版本
//析构first到last中的对象
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
__destroy(first, last, value_type(first));
}
//判断元素的value type中是否有trivial destructor(不重要的析构函数)
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());
}
//如果元素的数值型别有non_trivial destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
for ( ; fitst < last; ++first) {
destroy(&*first);
}
}
//如果元素的数值型别有trivial destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __true_type) {}
//以下是destroy()第二版本针对迭代器char* 和 wchar_t*的特化版
inline void destroy(char*, char*) {}
inline void destroy(wchar_t*, wchar_t*) {}
一级配置器和二级配置器
二级配置器名为__default_alloc_template,其中
- 维护16个自由链表,负责16种小型区块的次配置能力。
- 内存池以malloc配置而得,如果内存不足,转调用一级配置器(一级配置器有处理程序)
- 如果需求区块的大小大于128字节,就转调用第一级配置器
一级配置器名为__malloc_alloc_template,其中
- allocate()直接使用malloc()
- deallocate()直接使用free()
- 模拟c++的set_new_handler()以处理内存不足的状况
空间配置函数allocate()
//n must be > 0
static void* allocate(size_t n) {
obj * volatile * my_free_list;
obj* result;
//大于128字节就调用第一级配置器
if (n > (size_t) __MAX_BYTES) {
return(malloc_alloc::allocate(n));
}
//寻找16个free lists中适当的一个
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if (result == 0) {
//如果没找到可用的node,则重新装填free list
void *r = refill(ROUND_UP(n));
return r;
}
//调整free list
*my_free_list = result->free_list_link;
return (result);
}
空间释放函数deallocate()
//p不能为0
static void deallocate(void* p, size_t n) {
obj* q = (obj *)p;
obj* volatile* my_free_list;
//大于128就调用第一级配置器
if (n > (size_t)__MAX_BYTES) {
malloc_alloc::deallocate(p, n);
return;
}
//寻找对应的free list
my_free_list = free_list + FREELIST_INDEX(n);
//调整free list,回收区块
q->free_list_link = *my_free_list;
*my_free_list = q;
}