STL中的空间配置器

SGI STL分为两级空间配置器:

以下代码展现了alloc中内存的调度

//alloc.h
#ifndef ALLOC_H
#define ALLOC_H

#if 0
#	include <new>
#	define __THROW_BAD_ALLOC throw bad_alloc
#elif !defined(__THROW_BAD_ALLOC)
#	include <iostream>
#	define __THROW_BAD_ALLOC cerr << "out of memory" << endl; exit(1)
#endif

//第一级配置器
//非型别参数inst没有起到作用
template <int inst>
class __malloc_alloc_template {
private:
	//以下函数用来处理内存不足的情况 oom  即 out of memory
	static void* oom_malloc(size_t);
	static void* oom_realloc(void*, size_t);
	static void (* __malloc_alloc_oom_handler)();
public:
	static void* allocate(size_t n) {
		void *result = malloc(n);		//第一级配置器直接使用malloc()
		//无法分配时使用oom_malloc()
		if(result == 0) {
			result = oom_malloc(n);
		}
		return result;
	}

	static void* dellocate(void *p, size_t) {
		free(p);						//第一级配置器使用free()
	}

	static void* reallocate(void *p, size_t, size_t new_sz) {
		void *result = realloc(p, new_sz);
		if(result == 0) {
			result = oom_realloc(p, new_sz);
		}
		return result;
	}

	//仿真c++的set_new_handler()机制,指定自己的out_memory_handler
	//set_malloc_handler函数 函数参数void (*f)()
	//					  返回类型void (*f)()
	static void (*set_malloc_handler(void (*f)()))() {
		void (*old)() = __malloc_alloc_oom_handler;
		__malloc_alloc_oom_handler = f;
		return old;
	}
};

//out_of_memory handler初值设为0
template <int inst>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;

template <int inst>
void* __malloc_alloc_template<inst>::oom_malloc(size_t n) {
	void (*my_malloc_handler)();
	void *result;

	for(;;) {	//不断地尝试释放,配置,再释放,再配置^
		my_alloc_handler = __malloc_alloc_oom_handler;
		if(my_alloc_handler == 0) {
			__THROW_BAD_ALLOC;
		}
		(*my_malloc_handler)();	//调用处理例程,企图释放内存
		result = malloc(n);
		if(result != 0) {
			return result;
		}
	}
}

//与oom_malloc类似
template <int inst>
void* __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n) {
	void (*my_malloc_handler)();
	void *result;

	for(;;) {
		my_malloc_handler = __malloc_alloc_oom_handler;
		if(my_malloc_handler = 0) {
			__THROW_BAD_ALLOC;
		}
		(*my_malloc_handler)();
		result = realloc(p, n);
		if(result != 0) {
			return result;
		}
	}
}

typedef __malloc_alloc_template<0> malloc_alloc;
//end(第一级配置器)

//第二级配置器
enum {__ALIGN = 8};						//小型区块的上调边界
enum {__MAX_BYTES = 128};					//小型区块的上限
enum {__NFREELISTS = __MAX_BYTES/__ALIGN};	//free_lists的个数

template <bool threads, int inst>
class __default_alloc_template {
private:
	//ROUND_UP()将bytes上调至8的倍数
	static size_t ROUND_UP(size_t bytes) {
		return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1));
	}
private:
	//free_lists的节点构造
	union obj {
		union obj *free_list_link;
		char client_data[1];
	};
private:
	//16个free_lists
	static obj * volatile free_list[__NFREELISTS];
	//此函数可根据区块的大小,决定使用第n号free_list, n从0开始
	static size_t FREELIST_INDEX(size_t bytes) {
		return (((bytes) + __ALLIGN-1)/__ALIGN - 1);
	}
	//返回一个大小为n的对象,并可能加入大小为n的其它区块到free_list
	static void* refill(size_t n);
	//配置一大块空间,可容纳nobjs个大小为size的区域
	//如果配置nobjs个区块有所不便,nobjs可能会降低
	static char* chunk_alloc(size_t size, int &nobjs);

	//块的状态
	static char *start_free;		//内存池起始位置,只在chunk_alloc()中变化
	static char *end_free;			//内存池结束位置,只在chunk_alloc()中变化
	static size_t heap_size;
public:
	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) {
			//没有找到可用的free_list,准备重新填充free lists
			void *r = refill(ROUND_UP(n));
			return r;
		}
		//调整free_list
		*my_free_list = result->free_list_link;
		return result;
	}

	static void deallocate(void *p, size_t n) {
		obj *q = (obj *)p;
		obj * volatile *my_free_list;
		//大于128则调用第一级配置器
		if(n > 128) {
			malloc_alloc::dellocate(p, n);
			return;
		}
		//寻找对应的free list
		my_free_list = free_list + FREELIST_INDEX(n);
		//调整free_list,将q安插在区块头部
		q->free_list_link = *my_free_list;
		*my_free_list = q;
	}

	static void* reallocate(void *p, size_t old_sz, size_t new_sz);
};
//设定初值
template <bool threads, int inst>
char * __default_alloc_template<threads, inst>::start_free = 0;

template <bool threads, int inst>
char * __default_alloc_template<threads, inst>::end_free = 0;

template <bool threads, int inst>
char * __default_alloc_template<threads, inst>::heap_size = 0;

template <bool threads, int inst>
typename __default_alloc_template<threads, inst>::obj * volatile 
__default_alloc_template<threads, inst>::free_list[__NFREELISTS] = 
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

//返回一个大小为n的对象,并且有时候会为适当的free list增加节点
//n已经被适当上调为8的倍数
template <bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n) {
	int nobjs = 20;
	//调用chunk_alloc(),尝试取得nobjs个区块作为free list的新节点
	char *chunk = chunk_alloc(n, nobjs);
	obj * volatile * my_free_list;
	obj *result;
	obj *current_obj, *next_obj;
	int i;
	//如果只获得一个区块,将这个区块分配给调用者,free list无新节点
	if(nobjs == 1) {
		return chunk;
	}
	//否则调整free list,纳入新节点
	my_free_list = free_list + FREELIST_INDEX(n);
	//以下在得到的块中建立free list
	result = (obj*)chunk;			//这一块返回给调用者
	*my_free_list = next_obj = (obj *)(chunk + n);
	//将各个free list节点串接起来
	for(i = 1; ; i++) {
		current_obj = next_obj;
		next_obj = (obj*)((char*)next_obj + n);
		if(nobjs - 1 == i) {
			current_obj->free_list_link = 0;
			break;
		} else {
			current_obj->free_list_link = next_obj;
		}
	}
	return result;
}

//内存池
//nobjs是引用调用的
template <bool threads, int inst>
char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int &nobjs) {
	char *result;
	size_t total_bytes = size * nobjs;
	size_t bytes_left = end_free - start_free;			//内存池剩余空间

	if(bytes_left >= total_bytes) {
		//内存池剩余空间完全满足需求量
		result = start_free;
		start_free += total_bytes;
		return result;
	} else if(bytes_left >= size) {
		//内存池剩余空间不能完全满足需求,但足够供应一个(含)以上的区块
		nobjs = bytes_left/size;
		total_bytes = size * nobjs;
		result = start_free;
		start_free += total_bytes;
		return result;
	} else {
		//内存池剩余空间连一个区块的大小都无法提供
		size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);

		if(bytes_left > 0) {
			//内存池中还有一些零头,先配给适当的free list
			//寻找合适的free list
			obj * volatile * my_free_list = free_list + FREELIST_INDEX(bytes_left);
			//调整free list,将内存池中的残余空间编入
			((obj*)start_free)->free_list_link = *my_free_list;
			*my_free_list = (obj*)start_free;
		}
	
		//配置heap空间,用来补充内存池
		start_free = (char*)malloc(bytes_to_get);
		if(start_free == 0) {
			//heap空间不足,malloc()失败
			int i;
			obj * volatile * my_free_list, *p;
			for(i = size; i < __MAX_BYTES; i += __ALIGN) {
				my_free_list = free_list + FREELIST_INDEX(i);
				p = *my_free_list;
				if(p != 0) {		//free_list内尚有未用区块
					//调整free list 以释放未用区块
					*my_free_list = p->free_list_link;
					start_free = (char*)p;
					end_free = start_free + i;
					//递归调用自己,为了修正nobjs
					return chunk_alloc(size, nobjs);
				}
			}
			end_free = 0;		//如果出现意外(没有内存可用了)
			//调用第一级配置器,看看out_of_memory机制能否起作用,会抛出异常
			//或内存不足的情况得到改善
			start_free = (char *)malloc_alloc::allocate(bytes_to_get);
		}

		heap_size += bytes_to_get;
		end_free = start_free + bytes_to_get;
		//递归调用自己,为了修正nobjs
		return chunk_alloc(size, nobjs);
	}
}

#endif 



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值