C++模板与STL(六):内存空间配置器及内存池技术模拟

目录

1.容器内存空间配置器的概念 

2. Vector List deque的内存分配策略

2.1 Vector的内存分配策略模拟

2.2 List的内存分配策略

2.3 deque的内存分配策略

3.内存池技术及其仿真


1.容器内存空间配置器的概念 

Allocator:对容器与内存分布进行管理的承担者

C++模板与STL(六):内存空间配置器及内存池技术模拟_第1张图片

2. Vector List deque的内存分配策略

2.1 Vector的内存分配策略模拟

#include 
#include 
#include 
#include 
using namespace std;

//空间配置器的基类模板
template
struct Allocator_base {
	typedef _Ty value_type;
};

template
struct Allocator_base {
	typedef _Ty value_type;
};

//空间配置器的类模板设计
template
class Allocator :public Allocator_base<_Ty> {
public:
	//内嵌数据类型表
	typedef typename std::size_t size_type;
	typedef typename std::ptrdiff_t difference_type;
	typedef _Ty* pointer;
	typedef const _Ty* const_pointer;
	typedef _Ty& reference;
	typedef const _Ty& const_reference;
	typedef Allocator_base<_Ty> _Mybase;
	typedef typename _Mybase::value_type value_type;

	//配置器类型的嵌入类型
	template
	struct rebind {
		typedef Allocator<_U>other;
	};

	//构造函数
	Allocator()throw() {

	}
	Allocator(const Allocator&)throw() {}

	//可以接受不同类型的其他allocator的拷贝构造
	template
	Allocator(const Allocator<_otherAll>&)throw() {}

	~Allocator()throw()
	{

	}

	//请求内存空间
	pointer allocate(size_type num, typename Allocator<_Ty>::const_pointer hint = 0) {
		//显示一下内存空间发呢配信息
		static int i = 0;
		i++;
		cout << endl;
		cout << "第" << i << "次分配" << "-----------------------" << endl;
		cout << "本次需要分配可容纳" << num << "个元素空间" << endl;
		return (pointer)(::operator new(num * sizeof(_Ty)));
	}

	//在已经请求的内存空间中构造容器元素对象:operator new之后,用placement new指向
	void construct(pointer p, const_reference value) {
		new(p)_Ty(value);
	}

	//析构容器元素对象
	void destroy(pointer p) {
		p->~_Ty();
	}

	//释放已有的内存空间
	void deallocate(pointer p, size_type size) {
		::operator delete(p);
	}

};

//调用
template
void print(vector<_T, Allocator<_T>>& iv) {
	cout << "现在空间可容纳" << iv.capacity() << "个元素";
	cout << "\t 容器当前所存储元素数目:" << iv.size() << endl;
	cout << "容器中的元素数据:";
	for_each(iv.begin(), iv.end(), [](int n) {cout << " " << n; });
	cout << endl;
}

int main() {
	int a[] = { 1,2,3 };
	vector>vec(a, a + 3);
	print(vec);
	for (int i = 1; i < 10; i++) {
		vec.push_back(10 * i);
		print(vec);
	}
	return 0;
}

C++模板与STL(六):内存空间配置器及内存池技术模拟_第2张图片

可以看到每次分配的内存空间均为上次的1.5倍,这也是VS编译器所采取的策略。

不同C++编译器分配内存策略不同,例如g++就是2倍。

2.2 List的内存分配策略

对之前的代码做以下修改,变为list的,其他代码保持不变:

//调用
template
void print(list<_T, Allocator<_T>>& iv) {
	//cout << "现在空间可容纳" << iv.capacity() << "个元素";
	cout << "\t 容器当前所存储元素数目:" << iv.size() << endl;
	cout << "容器中的元素数据:";
	for_each(iv.begin(), iv.end(), [](int n) {cout << " " << n; });
	cout << endl;
}

int main() {
	int a[] = { 1,2,3 };
	//vector>vec(a, a + 3);
	list>myList(a, a + 3);
	print(myList);
	for (int i = 1; i < 5; i++) {
		myList.push_back(10 * i);
		print(myList);
	}
	return 0;
}

 C++模板与STL(六):内存空间配置器及内存池技术模拟_第3张图片

可以看到list的分配内存方式是一个一个分配的,需要一个就分配一个,不留余量。 

2.3 deque的内存分配策略

//调用
template
void print(deque<_T, Allocator<_T>>& iv) {
	//cout << "现在空间可容纳" << iv.capacity() << "个元素";
	cout << "\t 容器当前所存储元素数目:" << iv.size() << endl;
	cout << "容器中的元素数据:";
	for_each(iv.begin(), iv.end(), [](int n) {cout << " " << n; });
	cout << endl;
}

int main() {
	int a[] = { 1,2,3 };
	//vector>vec(a, a + 3);
	//list>myList(a, a + 3);
	deque>deq(a, a + 3);
	print(deq);
	for (int i = 1; i < 200; i++) {
		deq.push_back(i);
		//print(deq);
	}
	return 0;
}

C++模板与STL(六):内存空间配置器及内存池技术模拟_第4张图片

 deque每次分配固定大小内存,每次4个,逐次累加。

3.内存池技术及其仿真

C++模板与STL(六):内存空间配置器及内存池技术模拟_第5张图片

C++模板与STL(六):内存空间配置器及内存池技术模拟_第6张图片C++模板与STL(六):内存空间配置器及内存池技术模拟_第7张图片

#include 
#define MEMPOOL_ALIGNMENT 8
using namespace std;

//内存块
template
struct MemoryBlock{
	//表域
	int nSize;//内存块大小,以字节为单位
	int nFree;//表示内存剩余可分配的单位
	int nFirst;//首个剩余单位的序号

	MemoryBlock* pNext;
	char aData[1];//内存空间开始位置标记


	MemoryBlock(int nUnitSize, int nUninAmount) :
		nSize(nUnitSize* nUninAmount), nFree(nUninAmount - 1), nFirst(1), pNext(nullptr)
	{
		//下一个可以分配的单位序号需要记录当前单元的强两个字节
		char* ppData = aData;
		cout << "存储区首地址ppData=" << (int)*ppData << endl;
		for (int i = 1; i < nUninAmount; i++) {
			//在当前存储单位空间 存储下一个可分配的单位序号
			(*(unsigned short*)ppData) = i;
			ppData += nUnitSize;
		}
		cout << "内存块的构造函数被调用了" << endl;
	}

	//nUnitSize:存储单位大小
	//nUnitAmount:内存块的规模(数量)
	void* operator new(size_t, int nUnitSize, int nUnitAmount) {
		cout << "分配内存空间并创建MemoryBlock" << endl;
		return ::operator new(sizeof(MemoryBlock) + nUnitSize * nUnitAmount);
	}

	void operator delete(void* pBlock) {
		cout << "调用了内存的析构" << endl;
	}
};

//内存池 Mempool
template
struct MemoryPool
{
	int nInitSize;
	int nGrowSize;
	int nUnitSize;
	MemoryBlock<_T>* pBlock;

	MemoryPool(int _nGrowSize = 10, int _nInitSize = 3) {
		cout << "调用了内存池的构造函数" << endl;
		nInitSize = _nInitSize;
		nGrowSize = _nGrowSize;

		pBlock = nullptr;
		nUnitSize = (sizeof(_T));

		//纯出单位的大小调整
		if (sizeof(_T) > 4) {
			//8字节对齐
			nUnitSize = (sizeof(_T) + (MEMPOOL_ALIGNMENT - 1)) &
				~(MEMPOOL_ALIGNMENT - 1);
		}
		else {
			if (sizeof(_T) < 2) { nUnitSize = 2; }
			else { nUnitSize = 4; }
		}
	}

	~MemoryPool() {
		MemoryBlock<_T>* pMyBlock = pBlock;
		while (pMyBlock != nullptr) {
			pMyBlock = pMyBlock->pNext;
			delete(pMyBlock);
		}
		cout << "调用了内存池的析构函数" << endl;
	}

	void* allocate(size_t num) {
		for (int i = 0; i < num; i++) {
			if (pBlock == nullptr) {
				//创建首个内存块
				pBlock = (MemoryBlock<_T>*)new(nUnitSize, nInitSize)MemoryBlock<_T>(nUnitSize, nInitSize);
				return (void*)pBlock->aData;
			}
			//为内存寻求合适的内存块
			MemoryBlock<_T>* pMyBlock = pBlock;
			while (pMyBlock != nullptr && pMyBlock->nFree == 0) {
				pMyBlock = pMyBlock->pNext;
			}
			if (pMyBlock != nullptr) {
				cout << "内存空间已经找到,First=" << pMyBlock->nFirst << endl;
				char* pFree = pMyBlock->aData + pMyBlock->nFirst * nUnitSize;
				pMyBlock->nFirst = *((unsigned short*)pFree);
				pMyBlock->nFree--;
				return (void*)pFree;
			}
			else {
				//说明内存用完了
				if (nGrowSize == 0) {
					return nullptr;
				}
				cout << "分配新内存" << endl;
				pMyBlock = (MemoryBlock<_T>*)new (nUnitSize, nGrowSize)MemoryBlock<_T>(nUnitSize, nGrowSize);

				if (pMyBlock == nullptr) {
					return nullptr;
				}
				//如果成功那么,将新内存插入链表
				pMyBlock->pNext = pBlock;
				pBlock = pMyBlock;
				return (void*)pMyBlock->aData;
			}
		}
	}

	void free(void* pFree) {
		cout << "释放存储单位的空间" << endl;
		//找到p所在的内存块
		MemoryBlock<_T>* pMyBlock = pBlock;
		MemoryBlock<_T>* PreBlock = nullptr;

		while (pMyBlock != nullptr && (pBlock->aData > pFree) 
			|| pMyBlock->aData + pMyBlock->nSize) {
			PreBlock = pMyBlock;
			pMyBlock = pMyBlock->pNext;
		}

		//该内存在本内存池中的指向位置
		if (pMyBlock != nullptr) {
			//修改数组链表
			*((unsigned short*)pFree) = pMyBlock->nFirst;
			pMyBlock->nFirst = (unsigned short)((unsigned long)pFree - (unsigned long)pMyBlock->aData) / nUnitSize;
			pMyBlock->nFree++;

			//判断是否需要向操作系统释放内存
			if (pMyBlock->nSize == pMyBlock->nFree * nUnitSize) {
				delete(pMyBlock);
			}
			else {
				PreBlock = pMyBlock->pNext;
				pMyBlock->pNext = pBlock;
				pBlock = pMyBlock;
			}
		}
	}
};

class UserCls {
	int s;
	double s1;
	double s2;
public:
	UserCls(int x) :s(x) {
		cout << "调用了UserCls的构造函数" << endl;
	}
	int get() { return s; }
	~UserCls()
	{
		cout << "调用了UserCls的析构函数" << endl;
	}
};

int main() {
	MemoryPoolM_Pool;

	UserCls* dp1 = (UserCls*)M_Pool.allocate(1);
	cout << "dp1=" << dp1 << endl;
	new(dp1)UserCls(111);
	cout << "dp1中的数据是" << dp1->get() << endl;
	cout << endl;

	UserCls* dp2 = (UserCls*)M_Pool.allocate(1);
	cout << "dp2=" << dp2 << endl;
	new(dp2)UserCls(222);
	cout << "dp2中的数据是" << dp2->get() << endl;
	cout << endl;

	UserCls* dp3 = (UserCls*)M_Pool.allocate(1);
	cout << "dp3=" << dp3 << endl;
	new(dp3)UserCls(333);
	cout << "dp3中的数据是" << dp3->get() << endl;
	cout << endl;

	UserCls* dp4 = (UserCls*)M_Pool.allocate(1);
	cout << "dp4=" << dp4 << endl;
	new(dp4)UserCls(444);
	cout << "dp4中的数据是" << dp4->get() << endl;
	cout << endl;

	UserCls* dp5 = (UserCls*)M_Pool.allocate(1);
	cout << "dp5=" << dp5 << endl;
	new(dp5)UserCls(555);
	cout << "dp5中的数据是" << dp5->get() << endl;
	cout << endl;

	return 0;
}

C++模板与STL(六):内存空间配置器及内存池技术模拟_第8张图片

你可能感兴趣的:(C++,c++,开发语言)