【SGI二级空间配置器】

开发环境

Windows 10 专业版

开发工具

Microsoft Visual Studio Community 2017版本15.9.12

参考书籍

《STL 源码剖析》

分析

SGI STL包含了一级空间配置器和二级空间配置器,其中一级空间配置器allocator采用malloc和free来
管理内存,和C++标准库中提供的默认allocator是一样的;而二级空间配置器allocator采用了基于
freelist原理的内存池机制实现内存管理。

重要数据结构

union _Obj {
		union _Obj* _M_free_list_link;
		char _M_client_data[1];    /* The client sees this.        */
	};

 

enum { _ALIGN = 8 };//对齐方式
enum { _MAX_BYTES = 128 };//字节在128字节以下使用二级空间配置器分配回收内存
enum { _NFREELISTS = 16 }; // _MAX_BYTES/_ALIGN
//16 个 free-lists
static _Obj* _S_free_list[_NFREELISTS];

 

//表示内存池
static char* _S_start_free;
static char* _S_end_free;
static size_t _S_heap_size;

 辅助函数

//将__bytes 上调至 8的倍数
static size_t _S_round_up(size_t __bytes);

//根据区块大小返回,决定使用第n号free-list.n从0计算
static  size_t _S_freelist_index(size_t __bytes);

主要函数

//配置一大块空间,可容纳nobjs个大小为"size"的区块
static char *_S_chunk_alloc(size_t __size, int &__nobjs)

//返回相应块数,在需要的情况下除了分配给用户的块需要关联起来
static void* _S_refill(size_t __n)

用户使用的函数

static void* allocate(size_t __n)

static void deallocate(void* __p, size_t __n)

实现代码

#include <iostream>
using namespace std;

class Allocator
{
private:
	union _Obj {
		union _Obj* _M_free_list_link;
		char _M_client_data[1];    /* The client sees this.        */
	};
	
	enum { _ALIGN = 8 };//对齐方式
	enum { _MAX_BYTES = 128 };//字节在128字节以下使用二级空间配置器分配回收内存
	enum { _NFREELISTS = 16 }; // _MAX_BYTES/_ALIGN

	//16 个 free-lists
	static _Obj* _S_free_list[_NFREELISTS];

	//表示内存池
	static char* _S_start_free;
	static char* _S_end_free;
	static size_t _S_heap_size;


	//将__bytes 上调至 8的倍数
	static size_t
	_S_round_up(size_t __bytes)
	{
		return (((__bytes)+(size_t)_ALIGN - 1) & ~((size_t)_ALIGN - 1));
	}
	//根据区块大小返回,决定使用第n号free-list.n从0计算
	static  size_t _S_freelist_index(size_t __bytes) {
		return (((__bytes)+(size_t)_ALIGN - 1) / (size_t)_ALIGN - 1);
	}
	//
	//配置一大块空间,可容纳nobjs个大小为"size"的区块
	static char *_S_chunk_alloc(size_t __size, int &__nobjs)
	{
		char* __result;
		size_t __total_bytes = __size * __nobjs;//本次约定申请的总空间大小
		size_t __bytes_left = _S_end_free - _S_start_free;//内存池的剩余空间大小

		//内存池的内存够用
		if (__bytes_left >= __total_bytes) {
			__result = _S_start_free;//本次申请的空间的首地址
			_S_start_free += __total_bytes;//更新当前内存池
			return(__result);
		}
		//只够分配大于等于一块但是不满足第一个if(就是不能按照约定分配)
		else if (__bytes_left >= __size) {
			__nobjs = (int)(__bytes_left / __size);//内存池剩余空间够多少块
			__total_bytes = __size * __nobjs;//当前需要向内存池申请的空间
			__result = _S_start_free;//分配
			_S_start_free += __total_bytes;//更新内存池
			return(__result);
		}
		//内存池可以分配的内存小于__size(一块都不能够成功分配)
		else {
			//当前要申请的空间大小=2*total_bytes(之后一半放入自由列表维护,一半放入内存池维护)
			size_t __bytes_to_get =
				2 * __total_bytes + _S_round_up(_S_heap_size >> 4);//附加的内存(为了效率,每次如果执行到这里都多分配一些块)
			// Try to make use of the left-over piece.
			//将内存池中剩余的内存还有利用价值
			if (__bytes_left > 0) {
				_Obj** __my_free_list =
					_S_free_list + _S_freelist_index(__bytes_left);

				((_Obj*)_S_start_free)->_M_free_list_link = *__my_free_list;
				*__my_free_list = (_Obj*)_S_start_free;
			}
			//内存池首地址指向新的申请的空间
			_S_start_free = (char*)malloc(__bytes_to_get);
			//如果申请失败
			if (nullptr == _S_start_free) {
				size_t __i;
				_Obj** __my_free_list;
				_Obj* __p;
				// Try to make do with what we have.  That can't
				// hurt.  We do not try smaller requests, since that tends
				// to result in disaster on multi-process machines.
				for (__i = __size;
					__i <= (size_t)_MAX_BYTES;
					__i += (size_t)_ALIGN) {
					__my_free_list = _S_free_list + _S_freelist_index(__i);
					__p = *__my_free_list;
					//freelist内尚有未用的区块
					if (0 != __p) {
						*__my_free_list = __p->_M_free_list_link;
						_S_start_free = (char*)__p;
						_S_end_free = _S_start_free + __i;
						return(_S_chunk_alloc(__size, __nobjs));
						// Any leftover piece will eventually make it to the
						// right free list.
					}
				}
				_S_end_free = nullptr;	// In case of exception.
				_S_start_free = (char*)malloc(__bytes_to_get);
				// This should either throw an
				// exception or remedy the situation.  Thus we assume it
				// succeeded.
			}
			//内存池总容量(修正内存池参数)
			_S_heap_size += __bytes_to_get;
			_S_end_free = _S_start_free + __bytes_to_get;
			//递归调用,修正__nobjs
			return(_S_chunk_alloc(__size, __nobjs));
		}
	}

	//返回相应块数,在需要的情况下除了分配给用户的块需要关联起来
	static void* _S_refill(size_t __n)
	{
		int __nobjs = 20;
		char* __chunk = _S_chunk_alloc(__n, __nobjs);
		_Obj** __my_free_list;
		_Obj* __result;
		_Obj* __current_obj;
		_Obj* __next_obj;
		int __i;

		//如果只获得了一个区块,这个区块分配给用户,无新区块无需修正
		if (1 == __nobjs) return(__chunk);

		//找到在freelist中的位置
		__my_free_list = _S_free_list + _S_freelist_index(__n);

		//
		/* Build free list in chunk */
		__result = (_Obj*)__chunk;
		*__my_free_list = __next_obj = (_Obj*)(__chunk + __n);//除了第一块都需要加入自由列表

		//关联剩余区块
		for (__i = 1; ; __i++) {
			__current_obj = __next_obj;
			__next_obj = (_Obj*)((char*)__next_obj + __n);
			if (__nobjs - 1 == __i) {
				__current_obj->_M_free_list_link = 0;
				break;
			}
			else {
				__current_obj->_M_free_list_link = __next_obj;
			}
		}
		return(__result);
	}

public:
	//向空间配置器申请空间
	static void* allocate(size_t __n)
	{
		void* __ret = nullptr;

		if (__n > (size_t)_MAX_BYTES) {
			__ret = malloc(__n);
		}
		else {
			_Obj** __my_free_list
				= _S_free_list + _S_freelist_index(__n);
			// Acquire the lock here with a constructor call.
			// This ensures that it is released in exit or during stack
			// unwinding.
			_Obj* __result = *__my_free_list;
			if (__result == 0)
				__ret = _S_refill(_S_round_up(__n));
			else {
				*__my_free_list = __result->_M_free_list_link;
				__ret = __result;
			}
		}

		return __ret;
	}
	//向空间配置器归还空间
	static void deallocate(void* __p, size_t __n)
	{
		if (__n > (size_t)_MAX_BYTES)
			free(__p);
		else {
			_Obj**  __my_free_list
				= _S_free_list + _S_freelist_index(__n);
			_Obj* __q = (_Obj*)__p;

			// acquire lock
			__q->_M_free_list_link = *__my_free_list;
			*__my_free_list = __q;
			// lock is released here
		}
	}
};
//初始化静态成员变量

char *Allocator::_S_start_free = nullptr;
char *Allocator::_S_end_free = nullptr;
size_t Allocator::_S_heap_size = 0;
Allocator::_Obj* Allocator::_S_free_list[_NFREELISTS];

//类Allocator成员函数实现

int main()
{
	Allocator allocator; 
	int *arr = (int*)allocator.allocate(sizeof(int) * 10);
	for (int i = 0; i < 10; i++)
		arr[i] = (rand() % 100 + 1);
	allocator.deallocate(arr, 40);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值