SGI STL空间配置器源码刨析
SGI STL一级空间配置器和二级空间配置器,一级allocator采用malloc和free管理内存,二级是基于内存池实现的。
SGI STL 对于容器空间配置器选择
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class vector;
对于vector使用的默认空间配置器__STL_DEFAULT_ALLOCATOR,就是下面这两个宏定义的allocator 和 alloc。
# ifdef __STL_USE_STD_ALLOCATORS // 使用STL标准的(STD)的空间配置器,一级空间配置器 alloator
# define __STL_DEFAULT_ALLOCATOR(T) allocator< T >
# else // 否则使用二级空间配置器 alloc
# define __STL_DEFAULT_ALLOCATOR(T) alloc
# endif
一级空间配置器
template <int __inst>
class __malloc_alloc_template; // 主要的类
二级空间配置器
typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
可以看到SGI STL默认使用的是二级空间配置器,另外__NODE_ALLOCATOR_THREADS在宏默认是true,所以SGI STL的容器空间配置器默认是线程安全的,在下面的代码中大家就可以看到。
template <bool threads, int inst>
class __default_alloc_template; // 主要的类
SGI STL一级空间配置器 (allocator)
template <class _Tp>
class allocator
{
typedef alloc _Alloc;
public:
// allocator实现
_Tp* allocate(size_type __n, const void* = 0)
{
return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp))) : 0;
}
// deallocator实现
void deallocate(pointer __p, size_type __n)
{
_Alloc::deallocate(__p, __n * sizeof(_Tp));
}
// construct实现
void construct(pointer __p, const _Tp& __val)
{
new(__p) _Tp(__val); // 定位new
}
// destroy实现
void destroy(pointer __p)
{
__p->~_Tp();
}
};
可以看出SGI STL的一级空间配置器的construct和destroy的实现和c++标准库STL中的一级空间配置器相同
在对上面的 alloc 进行深入查看
typedef malloc_alloc alloc; // 在查看malloc_alloc实现
typedef __malloc_alloc_template<0> malloc_alloc;
// 在对 __malloc_alloc_template 查看,实现如下
template <int __inst>
class __malloc_alloc_template
{
public:
static void* allocate(size_t __n)
{
void* __result = malloc(__n);
if (0 == __result) __result = _S_oom_malloc(__n);
return __result;
}
static void deallocate(void* __p, size_t /* __n */)
{
free(__p);
}
};
最终可以看到,allocate的底层实现就是malloc,deallocate的底层实现就是调用free,和C++标准STL库的底层实现一样。
SGI STl 的二级空间配置器
重要的一些定义
enum {
_ALIGN = 8}; // 内存对齐大小,也就是chunk块之间的增长大小8,16,24,...
enum {
_MAX_BYTES = 128}; // 最大的chunk块的字节数
enum {
_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN // 共有多少不同大小的chunk块,128/8 = 16
union _Obj
{
union _Obj* _M_free_list_link; // 自由链表的指针
char _M_client_data[1];
}; // chunk块的信息,
static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; // 管理自由链表的数组,如下图所示,类似于Glibc
// 数组中的成员都是__Obj*,每个指针都被赋值为0
// 对于数组使用volatile修饰,确保多线程环境中,对于每个线程都是可见的。
template <bool __threads, int __inst>
typename __default_alloc_template<__threads, __inst>::_Obj* __STL_VOLATILE
__default_alloc_template<__threads, __inst> ::_S_free_list[
# if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC)
_NFREELISTS
# else
__default_alloc_template<__threads, __inst>::_NFREELISTS
# endif
] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; // 全为0
// Chunk allocation state. 记录chunk块的信息
static char* _S_start_free;
static char* _S_end_free;
static size_t _S_heap_size;
// chunk块的三个状态的初始值都为0
template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_start_free = 0