之前大概写过SGI STL相关的东西有关SGI STL,讲了讲空间配置器的原理,这一系列就剖析一下源码。
目录
下面就看看重要成员信息:
两个辅助接口函数:
关于C++的STL的空间配置器allocator的实现就是分了四部分:
- allocate:负责给容器开辟内存:底层就是malloc
- deallocate:负责给容器释放内存:底层就是free
- construct:负责给榕溪构造一个对象:定位new
- destroy:负责析构容器对象: p->~T()
拿C++STL里vector举例:
template<typename T,typename_Alloc=allocator<T>> class vector{ };
在C++STL里空间配置器做的事情就是分离了对象内存的开辟,释放,对象构造,析构
我们看SGI STL的实现还是找到vector看他push_back实现会发现
他的构造析构都是定义的全局的函数模板
SGI STL两个allocator的实现还是一级的是malloc和free,和C++STL基本无差,不过二级的用内存池的方式实现就复杂了
进到空间配置器源码看看
我们根据alloc层层找进去能看到SGI STL一级底层确实调的是malloc和free,和C++标准实现一样
直接进到二级配置器去看看
我们能看到人家写个这个__NODE_ALLOCATOR_THREADS,在线程里使用,说明SGI STL设计者保证了容器啊什么在多线程里的安全性,能直接去用。像C++ STL那就不是线程安全的了
这就到了二级空间配置器的实现
先给出实现图
下面就看看重要成员信息:
内存池的粒度信息
#if defined(__SUNPRO_CC) || defined(__GNUC__)
// breaks if we make these template class members:
enum {_ALIGN = 8};//对齐八字节
enum {_MAX_BYTES = 128};//最大字节
enum {_NFREELISTS = 16}; //自由链表的个数 // _MAX_BYTES/_ALIGN
#endif
每一个内存块的头信息
//将_bytes上调至最邻近的8的倍数
static size_t
_S_round_up(size_t __bytes)
{ return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }
__PRIVATE:
union _Obj {
union _Obj* _M_free_list_link;//自由链表的连接
char _M_client_data[1]; /* The client sees this. */
};
在源码里面多线程下有很多volatile,为的就是防止数据缓存,每次都从内存读数据
s_free_list就是数组名,_NFREELISTS 就是元素个数,挂了多少个链表
template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_start_free = 0;
template <bool __threads, int __inst>
char* __default_alloc_template<__threads, __inst>::_S_end_free = 0;
template <bool __threads, int __inst>
size_t __default_alloc_template<__threads, __inst>::_S_heap_size = 0;
两个辅助接口函数:
//将_bytes上调至最邻近的8的倍数
static size_t _S_round_up(size_t __bytes)
{ return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }
//返回小于_bytes大小的chunk块位于free-list的编号
static size_t _S_freelist_index(size_t __bytes) {
return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);
}
ALIGN是8,用size_t无符号整型强转成4字节,然后再取反,把两个按位与
1~8=>8
9~16=>16
....
(size_t) _ALIGN-1=>00000000 00000000 00000000 00000111 后面加_bytes
~((size_t) _ALIGN - 1)=>11111111 11111111 11111111 11111000
我们要申请1字节就会定位到第一个chunk块,0下标8字节位置,从链表上分配出去8字节
本节over