SGI STL二级空间配置器源码剖析

通过剖析SGI STL二级空间配置器内存池源码深入理解其实现原理

SGI STL包含了一级空间配置器和二级空间配置器,其中一级空间配置器allocator采用malloc和free来

管理内存,和C++标准库中提供的allocator是一样的,但其二级空间配置器allocator采用了基于freelist

自由链表原理的内存池机制实现内存管理。

空间配置器的相关定义

template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >

class vector : protected _Vector_base<_Tp, _Alloc>

可以看到,容器的默认空间配置器是__STL_DEFAULT_ALLOCATOR( _Tp),它是一个宏定义,如下:

# ifndef __STL_DEFAULT_ALLOCATOR
	# ifdef __STL_USE_STD_ALLOCATORS
		# define __STL_DEFAULT_ALLOCATOR(T) allocator< T >
	# else
		# define __STL_DEFAULT_ALLOCATOR(T) alloc
	# endif
# endif

从上面可以看到__STL_DEFAULT_ALLOCATOR通过宏控制有两种实现,一种是allocator< T >,另一种

是alloc,这两种分别就是SGI STL的一级空间配置器和二级空间配置器的实现。

template <int __inst>

class __malloc_alloc_template

// 一级空间配置器内存管理类 -- 通过malloc和free管理内存

template <bool threads, int inst>

class __default_alloc_template { // 二级空间配置器内存管理类 -- 通过自定义内存池实现内存管理

重要类型和变量定义

// 内存池的粒度信息

enum {_ALIGN = 8};//字节对齐到以8为单位

enum {_MAX_BYTES = 128};

enum {_NFREELISTS = 16};

// 每一个内存chunk块的头信息

union _Obj {

union _Obj* _M_free_list_link;

char _M_client_data[1];

/* The client sees this. */

};

// 组织所有自由链表的数组,数组的每一个元素的类型是_Obj*,全部初始化为0

static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS];//自由链表
// Chunk allocation state. 记录内存chunk块的分配情况

static char* _S_start_free;

static char* _S_end_free;

static size_t _S_heap_size;

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); //bytes->8*n / 8}

内存池管理函数

// 分配内存的入口函数

static void* allocate(size_t __n)

// 负责把分配好的chunk块进行连接,添加到自由链表当中

static void* _S_refill(size_t __n);

// 分配相应内存字节大小的chunk块,并且给下面三个成员变量初始化

static char* _S_chunk_alloc(size_t __size, int& __nobjs);

// 把chunk块归还到内存池

static void deallocate(void* __p, size_t __n);

// 内存池扩容函数

template <bool threads, int inst>

void*

__default_alloc_template<threads, inst>::reallocate(void* __p,

size_t __old_sz,

size_t __new_sz);


二级空间配置器分配空间流程

  1. 二级空间配置器负责配置128字节以下的空间
  2. 空间配置器通过一个16个指针大小的自由链表管理内存空间
  3. 0-15号指针分别指向以8为单位递增的空间,首先都初始化为0
  4. 当容器申请空间(<128字节)时,空间配置器映射到以8为单位的空间大小n,找到对应的指针
  5. 若此时指针为0,
  • 5.1 没有备用空间则空间配置器申请40*n的空间,前一半通过函数划分为大小为n的chunk块,前一个指向后一个,并将第一个chunk块分配给容器
  • 5.2有备用空间,若够一个以上的n,则划分为大小为n的chunk,并分配一块给容器,将剩下的大小为n的chunk块,交给自由链表中对应的指针,将<n的碎片空间交给对应大小的指针(因为是以8为单位,所以一定能找到对应大小)
  • 5.3若不够一个n的,则将备用空间交给对应指针,再重新申请空间并走5.1
  1. 若指针已经指向划分好chunk的空间则直接分配一个chunk块给容器,并将自由链表的指针指向下一个chunk。
  2. 若分配失败则,遍历比n大的指针,找有没有空闲的chunk,分配给容器,若没找到,则调用回调函数,也许会释放空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值