模拟实现一个SGI空间配置器

List.h

#include<iostream>
#include<assert.h>
#include<string>
#include"Alloc.h"
#include"Iterator.h"
using namespace std;


//带头结点的双向循环链表--结构的优势->>>>操作都统一
template<class T>
struct __ListNode 
{
	T _data;
	struct __ListNode<T>* _prev;
	struct __ListNode<T>* _next;
	__ListNode(const T& x)
		:_data(x)
		,_prev(NULL)
		,_next(NULL)
	{}
	~__ListNode()
	{}
}; 

//T  T& T*
//T	 const T&	const T*
template<class T,class Ref,class Ptr>
struct __ListIterator
{

	typedef __ListNode<T> Node;
	typedef __ListIterator<T, Ref, Ptr> Self;
	
	//
	Node* _node;
	//
	
	typedef BidirectionalIteratorTag IteratorCategory;
	typedef T ValueType;//内置类型
	typedef Ptr Pointer;//指针
	typedef Ref Reference;//引用
	typedef size_t DifferenceType;//距离
	
	__ListIterator(Node* node)
		:_node(node)
	{}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &(operator*());
	}
	bool operator==(const Self& s)
	{
		return _node == s._node;
	}

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}
	Self operator++()
	{
		_node = _node->_next;
		return *this;
	}
	Self operator++(int)//后置
	{
		Self tmp = _node;
		_node = _node->_next;
		return tmp;
	}
	Self operator--()
	{
		_node = _node->_prev;
		return *this;
	}

	Self operator--(int)
	{
		Self tmp = _node;
		_node = _node->_prev;
		return tmp;
	}
};


template<class T,class Alloc = alloc>
class List
{
	typedef struct __ListNode<T> Node;
public:
	typedef __ListIterator<T, T&, T*> Iterator;
	typedef __ListIterator<T, const T&, const T*> ConstIterator;

	typedef ReverseIterator<ConstIterator> ConstReverseIterator;
	typedef ReverseIterator<Iterator> ReverseIterator;

	typedef SimpleAlloc<Node, Alloc> ListNodeAlloc;


	Iterator Begin()
	{
		return _head->_next;
	}

	//小心
	Iterator End()
	{
		return _head;
	}
	ReverseIterator RBegin()
	{
		return ReverseIterator(End());
	}

	ReverseIterator REnd()
	{
		return ReverseIterator(Begin());
	}

	// const List<int>* this
	ConstIterator Begin() const
	{
		return _head->_next;
	}

	ConstIterator End() const
	{
		return _head;
	}
	//构造 先申请空间 然后赋值
	Node* BuyNode(const T& x)
	{
		Node* node = ListNodeAlloc::Allocate();//分配空间
		try
		{
			new (node) Node(x);//  new Node(x);??
		}
		catch (...)
		{
			//进来这里说明构造失败
			ListNodeAlloc::Deallocate(node);
			throw;
		}
		return node;
	}
	//析构  先析构 然后回收空间
	void DestoryNode(Node* p)
	{
		p->~Node();
		ListNodeAlloc::Deallocate(p);
	}

	List()
	{
		
		_head = BuyNode(T());
		_head->_next = _head;
		_head->_prev = _head;
	}
	List(const List<T>& l)//这个只会在初始化的时候用到
	{
		//_head = new Node(T());
		_head = BuyNode(T());
		_head->_next = _head;
		_head->_prev = _head;

		/*
		Node* cur = l._head->_next;
		while (cur != l._head)
		{
			PushBack(cur->_data);
			cur = cur->_next;
		}*/
		ConstIterator it = l.Begin();
		while (it != l.End())
		{
			PushBack(*it);
			++it;
		}
	}
	~List()
	{
		Clear();
		//delete _head;
		DestoryNode(_head);
		_head = NULL;
	}

	void Clear()
	{
		Iterator it = Begin();
		while (it != End())
		{
			Node* del = it._node;
			++it;
			//delete del;
			DestoryNode(del);
		}

		_head->_next = _head;
		_head->_prev = _head;
	}
	//好好思考下
	List& operator=(List<T> l)
	{
		if (this != &l)
		{
			swap(_head, l._head);
		}
		return *this;
	}
	
	void PushBack(const T&x)
	{
		//Insert(_head,x);
		Insert(End(), x);
	}
	void PushFront(const T&x)
	{
		//Insert(_head->_next, x);
		Insert(Begin(), x);
	}
	void PopBack()
	{
		//Erase(_head->_prev);
		Erase(--End());
	}

	void PopFront()
	{
		//Erase(_head->_next);
		Erase(Begin());
	}
	//void Insert(Node* pos, const T& x)

	void Insert(Iterator pos, const T& x)
	{
		//assert(pos);
		在pos 的前面插入
		//Node* prev = pos->_prev;
		//Node* tmp = new Node(x);
		//tmp->_next = pos;
		//tmp->_prev = prev;
		//prev->_next = tmp;
		//pos->_prev = tmp;

		Node* cur = pos._node;
		Node* prev = cur->_prev;
		Node* tmp = BuyNode(x);
		prev->_next = tmp;
		tmp->_next = cur;
		tmp->_prev = prev;
		cur->_prev = tmp;

	}

	//void Erase(Node* pos)
	//{
	//	assert(pos&&pos!=_head);

	//	Node* prev = pos->_prev;
	//	Node* next = pos->_next;
	//	delete pos;
	//	next->_prev = prev;
	//	prev->_next = next;
	//}
	// 防御式 assert + const & -- 保守
	// 扩展 -> 即删即用
	Iterator Erase(Iterator& pos)
	{
		assert(pos != End());

		Node* prev = (pos._node)->_prev;
		Node* next = (pos._node)->_next;
		prev->_next = next;
		next->_prev = prev;

		//delete pos._node;
		DestoryNode(pos._node);

		pos._node = prev;

		//return next;
		return Iterator(next);
	}
private:
	Node* _head;
};
void PrintList(const List<int>& l)
{
	List<int>::ConstIterator it = l.Begin(); //const List<int>*
	while (it != l.End())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

void TestList()
{
	List<int> l;
	l.PushBack(1);
	l.PushBack(2);
	l.PushBack(3);
	l.PushBack(4);

	PrintList(l);

	cout << Distance(l.Begin(), l.End()) << endl;

	List<int>::ReverseIterator rIt = l.RBegin();
	while (rIt != l.REnd())
	{
		cout << *rIt << " ";
		++rIt;
	}
	cout << endl;
}
int main()
{
	TestList();
	system("pause");
	return 0;
}

Alloc.h

#pragma once
#include<iostream>
#include <stdarg.h>
using namespace std;
#define __DEBUG__

static string GetFileName(const string& path)
{
	char ch = '/';

#ifdef _WIN32
	ch = '\\';
#endif

	size_t pos = path.rfind(ch);
	if (pos == string::npos)
		return path;
	else
		return path.substr(pos + 1);
}
// 用于调试追溯的trace log
inline static void __trace_debug(const char* function,
	const char * filename, int line, char* format, ...)
{
	// 读取配置文件
#ifdef __DEBUG__
	// 输出调用函数的信息
	fprintf(stdout, "【 %s:%d】%s ", GetFileName(filename).c_str(), line, function);

	// 输出用户打的trace信息
	va_list args;
	va_start(args, format);
	vfprintf(stdout, format, args);
	va_end(args);
#endif
}

#define __TRACE_DEBUG(...)  \
	__trace_debug(__FUNCTION__ , __FILE__, __LINE__, __VA_ARGS__);

typedef void(*HANDLE_FUNC)();

template<int inst>

class __MallocAllocTemplate
{
private:
	static void* OOM_Malloc(size_t n)
	{
		void* ret;
		while (1)
		{
			if (__mallocAllocOomHandler == 0)
			{
				throw bad_alloc();
			}
			__mallocAllocOomHandler();//期望释放内存
			ret = malloc(n);
			if (ret)
				break;
		}
		return ret;

	}
	static HANDLE_FUNC __mallocAllocOomHandler;//句柄函数指针
public:
	static void* Allocate(size_t n)
	{
		__TRACE_DEBUG("到一级空间配置器申请内存.%d\n", n);

		void* result = malloc(n);
		if (0 == result)
			result = OOM_Malloc(n);

		return result;
	}
	static void Deallocate(void* p, size_t /*n*/)
	{
		free(p);
	}

	static HANDLE_FUNC SetMallocHandler(HANDLE_FUNC f)
	{
		HANDLE_FUNC old = __mallocAllocOomHandler;
		__mallocAllocOomHandler = f;
		return old;
	}
};
template<int inst>
HANDLE_FUNC __MallocAllocTemplate<inst>::__mallocAllocOomHandler = 0;

/
template<bool threads, int inst>
class __DefaultAllocTemplate {
public:
	static size_t FREELIST_INDEX(size_t bytes)//求出对应下标
	{
		return (((bytes)+__ALIGN-1)/ __ALIGN - 1);
		//(X +7)/8 -1;
	}
	static size_t ROUND_UP(size_t bytes)//非8倍数的整数上调到8的倍数
	{
		return (((bytes)+__ALIGN - 1)&~(__ALIGN - 1));
	}
	static char* ChunkAlloc(size_t n, size_t& nobjs)//想内存池去要
	{
		size_t totalBytes = n*nobjs;
		size_t leftBytes = _endFree - _startFree;

		__TRACE_DEBUG("需要%d bytes, 狭义内存池有多少%dbytes\n", totalBytes, leftBytes);

		if (leftBytes >= totalBytes)
		{
			char* ret = _startFree;
			_startFree += totalBytes;
			return ret;
		}
		else if (leftBytes > n)//够至少一个
		{
			nobjs = leftBytes / n;
			totalBytes = nobjs*n;
			char* ret = _startFree;
			_startFree += totalBytes;
			return ret;
		}
		else
		{
			//处理剩余内存

			if (leftBytes > 0)
			{
				size_t index = FREELIST_INDEX(leftBytes);
				//头插
				((Obj*)_startFree)->_freeListLink = _freeList[index];
				_freeList[index] = (Obj*)_startFree;
			}

			size_t bytesToGet = totalBytes * 2 + ROUND_UP(_heapSize);
			_startFree = (char*)malloc(bytesToGet);
			__TRACE_DEBUG("向系统申请%dbytes\n", bytesToGet);
			if (_startFree == NULL)
			{
				//尝试去更大的自由链表中去找
				for (size_t i = FREELIST_INDEX(n); i < __NFREELISTS; i++)
				{
					if (_freeList[i])
					{
						Obj* obj = _freeList[i];
						_freeList[i] = obj->_freeListLink;
						_startFree = (char*)obj;
						_endFree = _startFree + (i + 1)*__ALIGN;
						
						//回调自己,为了修正nobjs
						return ChunkAlloc(n, nobjs);
					}
				}
				_endFree = 0;//出现意外,到处都没内存可用了
				//调用第一级配置器,看看out-of-memory机制能否尽力
				_startFree = (char*)__MallocAllocTemplate<0>::Allocate(bytesToGet);
				//结果是抛出异常或者内存不足情况得到改善

			}
			_heapSize += bytesToGet;
			_endFree = _startFree + bytesToGet;
			return ChunkAlloc(n, nobjs);
		}
	}
	static void* Refill(size_t n)//扩充某个链表中节点下的空间
	{
		size_t nobjs = 20;
		char* chunk = ChunkAlloc(n, nobjs);

		__TRACE_DEBUG("在狭义内存池申请到%d个对象,返回一个,挂%d个到自由链表\n", nobjs, nobjs - 1);

		if (nobjs == 1)
			return chunk;

		size_t index = FREELIST_INDEX(n);
		Obj* cur = (Obj*)(chunk + n);
		_freeList[index] = cur;
		for (size_t i = 0; i < nobjs - 2; i++)
		{
			Obj* next = (Obj*)((char*)cur + n);
			cur->_freeListLink = next;
			cur = next;
		}
		cur->_freeListLink = NULL;
		
		return chunk;
	}
	static void* Allocate(size_t n)
	{
		if (n > __MAX_BYTES)
		{
			return __MallocAllocTemplate<0>::Allocate(n);
		}
		size_t index = FREELIST_INDEX(n);
		Obj* first = _freeList[index];
		if (first == NULL)
		{
			__TRACE_DEBUG("freeList[%d]下面没有挂对象,到狭义内存池进行申请\n", index);
			return Refill(ROUND_UP(n));
		}
		else
		{
			__TRACE_DEBUG("freeList[%d]下面有对象,取一个内存对象返回\n", index);
			_freeList[index] = first->_freeListLink;
			return first;
		}
	}
	static void Deallocate(void* p,size_t n)
	{
		if (n > __MAX_BYTES)
		{
			 __MallocAllocTemplate<0>::Deallocate(p, n);
			 return;
		}
		size_t index = FREELIST_INDEX(n);
		//头插
		Obj* obj = (Obj*)p;   //*************/  Node*------->Obj* 还有_freeListLink存下一个  注意这个size 也就是8 16 24 是个突破点
		obj->_freeListLink = _freeList[index];
		_freeList[index] = obj;
	}
private:
	enum { __ALIGN = 8 };
	enum { __MAX_BYTES = 128 };
	enum { __NFREELISTS = __MAX_BYTES / __ALIGN };

	union Obj
	{
		union Obj* _freeListLink;
		char client_data[1];    /* The client sees this. */
	};

	// 自由链表--管理内存块
	static Obj* _freeList[__NFREELISTS];

	// 内存池--狭义
	static char* _startFree;
	static char* _endFree;
	static size_t _heapSize; // 反馈调节 -- 内存池已经向系统省内请的内存大小
};
template<bool threads, int inst>
typename __DefaultAllocTemplate<threads, inst>::Obj*
__DefaultAllocTemplate<threads, inst>::_freeList[] = { 0 };

template<bool threads, int inst>
char* __DefaultAllocTemplate<threads, inst>::_startFree = 0;

template<bool threads, int inst>
char* __DefaultAllocTemplate<threads, inst>::_endFree = 0;

template<bool threads, int inst>
size_t __DefaultAllocTemplate<threads, inst>::_heapSize = 0;


# ifdef __USE_MALLOC
	typedef __MallocAllocTemplate<0> alloc;
#else
	typedef __DefaultAllocTemplate<false, 0> alloc;
#endif

template<class T, class Alloc>
class SimpleAlloc
{
public:
	static T* Allocate(size_t n)
	{
		return 0 == n ? 0 : (T*)Alloc::Allocate(n * sizeof(T));
	}
	static T* Allocate(void)
	{
		return (T*)Alloc::Allocate(sizeof(T));
	}
	static void Deallocate(T *p, size_t n)
	{
		if (0 != n) 
			Alloc::Deallocate(p, n * sizeof(T));
	}
	static void Deallocate(T *p)
	{
		Alloc::Deallocate(p, sizeof(T));
	}
};

Iterator.h

#pragma once
//
// 迭代器的型别
//
struct InputIteratorTag {};
struct OutputIteratorTag {};
struct ForwardIteratorTag : public InputIteratorTag {};
struct BidirectionalIteratorTag : public ForwardIteratorTag {};
struct RandomAccessIteratorTag : public BidirectionalIteratorTag {};

//
// Traits 就像一台“特性萃取机”,榨取各个迭代器的特性(对应的型别)
//
template <class Iterator>
struct IteratorTraits
{
	typedef typename Iterator::IteratorCategory IteratorCategory;
	typedef typename Iterator::ValueType        ValueType;
	typedef typename Iterator::DifferenceType   DifferenceType;
	typedef typename Iterator::Pointer           Pointer;
	typedef typename Iterator::Reference         Reference;
};

//特化版本
template <class T>
struct IteratorTraits<T*>
{
	typedef RandomAccessIteratorTag IteratorCategory;
	typedef T						ValueType;
	typedef size_t					DifferenceType;
	typedef T*						Pointer;
	typedef T&						Reference;
};

template <class T>
struct IteratorTraits<const T*>
{
	typedef RandomAccessIteratorTag IteratorCategory;
	typedef T						ValueType;
	typedef size_t					DifferenceType;
	typedef const T*			    Pointer;
	typedef const T&				Reference;
};

// O(N)
template<class Iterator>
size_t __Distance(Iterator first, Iterator last, InputIteratorTag)
{
	size_t n = 0;
	while (first != last)
	{
		++first;
		++n;
	}

	return n;
}

// O(1)
template<class Iterator>
size_t __Distance(Iterator first, Iterator last, RandomAccessIteratorTag)
{
	return last - first;
}

template<class Iterator>
size_t Distance(Iterator first, Iterator last)
{
	//return __Distance(first, last, Iterator::IteratorCategory());
	//萃取器
	return __Distance(first, last, IteratorTraits<Iterator>::IteratorCategory());
}

// 适配器
template<class Iterator>
struct ReverseIterator
{
	typedef ReverseIterator<Iterator> Self;
	Iterator _it;

	explicit ReverseIterator(Iterator it)
		:_it(it)
	{}
	//通过萃取器 取出对应的型别  在迭代器内部本身也有声明 (所以都用typename)
	typename IteratorTraits<Iterator>::Reference operator*()
	{
		//return *_it;

		Iterator tmp = _it;
		return *(--tmp);
	}

	typename IteratorTraits<Iterator>::Pointer operator->()
	{
		return &(operator*());
	}

	Self& operator++()
	{
		--_it;
		return *this;
	}

	Self& operator--()
	{
		++_it;
		return *this;
	}

	bool operator==(const Self& s)
	{
		return _it == s._it;
	}

	bool operator!=(const Self& s)
	{
		return _it != s._it;
	}
};

关于空间配置器十个问题


一、一二级配置器开放准则是什么?
整个设计究竟只开放第一级配置器,或是同时开放第二级配置器,取决于__USE_MALLOC是否被定义

二、什么是内碎片和外碎片?
操作系统频繁分配内存和回收内存的时候。这些6M,4M的小内存无法利用造成了外部碎片
自由链表所挂区块都是8的整数倍,因此当我们需要非8倍数的区块,往往会导致浪费,比如我只要1字节的大小,但是自由链表最低分配8块,也就是浪费了7字节,这7字节就是内碎片

三、为什么引入复杂的两级空间配置器?
1. 频繁使用malloc,free开辟释放小块内存带来的性能效率的低下
2. 内存碎片问题,导致不连续内存不可用的浪费

四、为什么所有成员函数都是静态的?
是为了在外面通过作用域就可以调用,而不需要构造对象

五、typename有什么作用?
  这个关键字用于指出模板声明(或定义)中的非独立名称(dependent names)是类型名,而非变量名

六、ROUNT_UP的实现原理是什么?
static size_t ROUND_UP(size_t bytes)//作用是将非8倍数的整数上调到8的倍数。
 {
        return (((bytes)+__ALIGN - 1) &~(__ALIGN - 1));
}

 round_up实现原理:
   以 bytes = 30为例:
   a. (30 + 7) = 37, 可以知道30的round_up为32, 给32加(8-1)的目的是让其(一定)大于32
   b. 这样的话,以十进制形式,37肯定可以表达为如下的形式:(x*8 + y),  并且可以肯定这个y的值小于8,上述37表达形式为:(32 + 5)
   c. 根据上述b步骤的形式,我们很自然的明白, 只要将 ((bytes) + 8-1) 转换为(x*8 + y)的形式后,然后再将y的值减去就达到目的了
   d. 总结上述思路,我们要做事情有两个,一是将 ((bytes) + 8-1) 转换为 (x*8 + y)的形式; 二是将(x*8 + y)中的y值清零
   e. 在十进制下,要完成上述任务,比较困难,而在二进制下,就非常好办
   f. 首先,将 ((bytes) + 8-1) 转换为(x*8 + y), 只要将 ((bytes) + 8-1)的值转为二进制,如以37为例,其二进制为: 00100101,这样写你可能看得还不是很直观,这样写 (00100)    (101), 这样就可以发现,第一个小括号里面的值就为(x*8), 第二个小括号里面的值就为(y); 接下来,我们的目的就很简单的, 将第二个小括号里面的所有位置为0即可, 参考上述网页中的规则“非运算和与运算结合,可以确保将指定位 清0, 故 & ~(__ALIGN - 1)的目的就是将第二个小括号中的位清0. 至此, 问题圆满解决。

七、引入两层配置器带来什么问题?
    1.内存碎片
    2.我们发现似乎没有释放自由链表所挂区块的函数?确实是的,由于配置器的所有方法,成员都是静态的,那么他们就是存放在静态区。释放时机就是程序结束,这样子会导致自由链表一直占用内存,自己进程可以用,其他进程却用不了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值