91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

STL中空間配置器(allocator)的簡單實現

發布時間:2020-07-25 18:01:03 來源:網絡 閱讀:424 作者:shangluyi 欄目:編程語言

包括一級空間配置器 和 二級空間配置器


#pragma once
#include <iostream>
using namespace std;


/*————————————*/
/*         一級空間配置器           */
/*————————————*/


typedef void(*ALLOC_OOM_FUN)();   //函數指針

template <int inst>					//這個模板參數并沒有使用,是預留的
class __MallocAllocTemplate
{
private:
	static ALLOC_OOM_FUN __sMallocAllocOomHandler;		//句柄函數,如果設置了,空間分配失敗就會調用它

	static void* OomMalloc(size_t n)
	{
		ALLOC_OOM_FUN MyMallocHandler;
		void *result;
		/*
			1:分配內存成功,直接返回
			2:分配失敗,則檢查是否有設置處理的MyMallocHandler,
			   如果有,則調用它以后再嘗試分配,并不斷重復,直到分配成功
			   如果沒有,則直接結束程序
		*/
		for (;;)
		{
			MyMallocHandler = __sMallocAllocOomHandler;
			if (MyMallocHandler)
			{
				MyMallocHandler();
				void *ret = malloc(n);
				if (ret)
				{
					return ret;
				}
			}
			else
			{
				throw bad_alloc();
			}
		}
		return result;
	}

	static void* OomRealloc(void *p, size_t n)
	{
		/*
			步驟同上
		*/
		ALLOC_OOM_FUN MyMallocHandler;
		for (;;)
		{
			MyMallocHandler = __sMallocAllocOomHandler;
			if (MyMallocHandler)
			{
				MyMallocHandler();
				void *ret = realloc(p, n);
				if (ret)
				{
					return ret;
				}
			}
			else
			{
				throw bad_alloc();
			}
		}
	}

public:
	static void* Allocate(size_t n)
	{
		//__TRACE_DEBUG("n:%u\n", n);
		void *result = malloc(n);	//第一級配置器直接使用malloc
		if (NULL == result)		// 0 == result
		{
			result = OomMalloc(n);
		}
		return result;
	}

	static void Deallocate(void *p, size_t /* n */)
	{
		//TRACE_DEBUG("(p:%p)\n". p);
		free(p);		//第一級配置器直接使用free()
	}

	static void*Reallocate(void *p, size_t/*old_sz*/, size_t new_sz)
	{
		void *result = realloc(p, new_sz);
		if (NULL == result)
		{
			result = OomRealloc(p, new_sz);
			return result;
		}
		return result;
	}

	/*
		設置句柄函數的函數
		函數名:SetMallocHandler
		參數:名為f的函數指針(指向要設置的新句柄)
		返回值:函數指針(指向原來的句柄函數)
	*/
	static void(*SetMallocHandler(void(*f)()))()
	{
		void(*old)() = __sMallocAllocOomHandler;
		__sMallocAllocOomHandler = f;
		return old;
	}

};

//將句柄函數指針初始化為空
template<int inst>
ALLOC_OOM_FUN __MallocAllocTemplate<inst>::__sMallocAllocOomHandler = NULL;



/*————————————*/
/*         二級空間配置器           */
/*————————————*/



template<bool threads, int inst>	//這兩個模板參數同樣并沒有使用,是預留的
class __DefaultAllocTemplate
{
public:
	enum { __ALIGN = 8 };												//排列基準值(間隔)
	enum { __MAX_BYTES = 128 };									//最大值,上限
	enum { __NFREELISTS = __MAX_BYTES / __ALIGN };	//自由鏈表的個數
													//自由鏈表(FreeLists)結點
	union Obj
	{
		union Obj *_FreeListLink;		//指向下一個內存塊的指針
		char ClientData[1];   //客戶端可見(測試用)
	};

	static Obj* volatile _FreeList[__NFREELISTS];   //自由鏈表
	static char* _StartFree;										//內存池起始位置
	static char* _EndFree;									//內存池結束位置
	static size_t _HeapSize;									//從系統堆分配的內存的總大小

public:
	//空間配置函數
	static void* Allocate(size_t n)
	{
		//__TRACE_DEBUG("(n ;%n)\n", n);

		//如果 n > __MAX_BYTES 就直接在一級空間配置器中獲取內存
		//否則在二級空間配置器中獲取內存

		if (n > (size_t)__MAX_BYTES)
		{
			return __MallocAllocTemplate<0>::Allocate(n);
		}

		void *ret = NULL;
		size_t index = FREELIST_INDEX(n);

		//1、如果自由鏈表中沒有內存,通過Refill填充
		//2、如果自由鏈表中有,則返回一個結點塊的內存
		//ps: 多線程環境需要考慮加鎖

		Obj *head = _FreeList[index];
		if (head == NULL)
		{
			return Refill(ROUND_UP(n));
		}
		else
		{
			//__TRACE_DEBUG("自由鏈表取內存 : _FreeList[%s]\n", index);
			_FreeList[index] = head->_FreeListLink;
			return head;
		}
	}

	//空間釋放函數
	static void Deallocate(void *p, size_t n)
	{
		//__TRACE_DEBUG("(釋放 p : %p, n : %u)\n", p, n);

		//若 n > __MAX_BYTES則直接還給一級配置器
		//否則放回自由鏈表
		if (n > __MAX_BYTES)
		{
			__MallocAllocTemplate<0>::Deallocate(p, n);
		}
		else
		{
			//ps : 多線程要考慮加鎖
			size_t index = FREELIST_INDEX(n);
			//頭插回自由鏈表
			Obj *tmp = (Obj*)p;
			( (Obj*)p ) ->_FreeListLink = _FreeList[index];
			_FreeList[index] = tmp;
		}
	}
	static void* Reallocate(void *p, size_t old_sz, size_t new_sz)
	{
		void *result;
		size_t copy_sz;

		//內存塊較大,改用一級空間配置器
		if (old_sz > (size_t)__MAX_BYTES && new_sz > __MAX_BYTES)
		{
			return __MallocAllocTemplate<0>::Reallocate(p, old_sz, new_sz);
		}

		//修改前和修改后的大小相同,不用修改
		if (ROUND_UP(old_sz) == ROUND_UP(new_sz))
		{
			return p;
		}

		//否則,分配一塊空間,并將原來空間的數據拷貝至新空間
		result = Allocate(new_sz);
		copy_sz = new_sz > old_sz ? old_sz : new_sz;		//如果new_sz 小于 old_sz 會丟失數據
		memcpy(result, p, copy_sz);
		Deallocate(p, old_sz);	//拷貝完后, 釋放原來的空間
		return result;
	}

private:
	//將bytes上調至8的倍數
	static size_t ROUND_UP(size_t bytes)
	{
		return ((bytes + __ALIGN - 1) & ~(__ALIGN - 1));
		//位運算,保證效率  比如14: 14 + 7 =  21 (0x0001 0101)    和  (0x1000) 進行 & ,結果是: (0x0001 0000) 即 16
	}

	//選擇使用哪個自由鏈表
	static size_t FREELIST_INDEX(size_t bytes)
	{
		return((bytes + __ALIGN - 1) / __ALIGN - 1);
	}

private:
	//獲得大塊內存填充到自由鏈表中
	static void* Refill(size_t n)
	{
		//__TRACE_DEBUG("(n : %u)\n", n);

		//分配n bytes的內存,如果不夠則能分配多少是多少
		int nobjs = 20;	//一次要獲得的數目(一大塊內存)
		char *chunk = ChunkAlloc(n, nobjs);		//試圖獲得nobjs塊內存,每塊內存的大小為n,并把實際獲得的內存數賦予nobjs

		//如果只分配到一塊,則直接返回這塊內存
		if (nobjs == 1)
		{
			return chunk;
		}

		Obj *result;
		Obj *cur;
		size_t index = FREELIST_INDEX(n);		//根據n選擇要存放的鏈表
		result = (Obj*)chunk;

		//把剩余的塊鏈鏈接到自由鏈表上面
		cur = (Obj*)(chunk + n);
		_FreeList[index] = cur;
		for (int i = 2; i < nobjs; ++i)
		{
			cur->_FreeListLink = (Obj*)(chunk + n * i);
			cur = cur->_FreeListLink;
		}
		cur->_FreeListLink = NULL;
		return result;
	}

	static char* ChunkAlloc(size_t size, int &nobjs)
	{
		char *result;
		size_t TotalBytes = size * nobjs;
		size_t BytesLeft = _EndFree - _StartFree;   //內存池的剩余空間

		/*
			1、內存池中內存足夠,即BytesLeft >= TotalBytes時,直接從內存池中取出
			2、內存池中的內存不足,但足夠一塊時,即 Bytesleft >= size時,也直接取出來
			3、內存池中內存連一塊內存也不夠的時候,從系統堆中分配大塊內存到內存池中
		*/
		if (BytesLeft >= TotalBytes)		//1
		{
			//__TRACE_DEBUG("內存池中內存足夠分配 %d 個對象\n", nobjs);
			result = _StartFree;
			_StartFree += TotalBytes;
			return result;
		}
		else if (BytesLeft >= size)		//2
		{
			//__TRACE_DEBUG("內存池中內存不夠分配 %d 個對象, 只能分配  %d 個對象 \n", nobjs, BytesLeft / size);
			result = _StartFree;
			nobjs = BytesLeft / size;
			_StartFree += nobjs * size;

		}
		else											//3
		{
			//如果內存中還有小塊剩余內存(零頭),則將它頭插到合適的自由鏈表
			if (BytesLeft > 0)
			{
				size_t index = FREELIST_INDEX(BytesLeft);
				((Obj*)_StartFree)->_FreeListLink = _FreeList[index];
				_FreeList[index] = ((Obj*)_StartFree);
				_StartFree = NULL;
				//__TRACE_DEBUG("將內存池中剩余的空間,分配給 _FreeList[%d] \n", index);
			}

			//從系統堆分配兩倍+已分配的 _HeapSize / 8 的內存分配到內存池中
			size_t BytesToGet = 2 * TotalBytes + ROUND_UP(_HeapSize >> 4);
			_StartFree = (char*)malloc(BytesToGet);
			//__TRACE_DEBUG("內存池空間不足,系統堆分配 %u bytes 內存\n", BytesToGet);


			// 如果在堆中內存分配失敗,則嘗試到自由鏈表中更大的節點中分配
			if (_StartFree == NULL)
			{
				//TRACE_DEBUG("系統堆已經沒有足夠內存  在自由鏈表中查找\n");
				//為什么要從大小為size的鏈表中開始找呢?因為如果是多線程,有可能剛好其他線程
				//有釋放大小為size的內存,也就是說,大小為size的鏈表有可能有內存可以用
				//所以從大小為size的鏈表開始向后找
				for (int i = size; i <= __MAX_BYTES; i += __ALIGN)
				{
					Obj *head = _FreeList[FREELIST_INDEX(size)];
					if (head) //找到了有可用的內存,將它摘下來
					{
						_StartFree = (char*)head;
						head = head->_FreeListLink;
						_EndFree = _StartFree + i;
						return ChunkAlloc(size, nobjs);
					}
				}

				_EndFree = 0;  //防止異常,防止野指針

				//在自由鏈表中也沒找到,則退到一級空間配置器,希望句柄函數能做一些處理,以得到內存

				//__TRACE_DEBUG("系統堆和自由鏈表中都沒有內存了,調到在一級配置器里做最后的嘗試\n");
				_StartFree =(char*) __MallocAllocTemplate<0>::Allocate(BytesToGet);
			}

			//從系統堆分配的總字節數(可用于下次分配時進行調節)
			_HeapSize += BytesToGet;
			_EndFree = _StartFree + BytesToGet;

			//遞歸調用獲取內存
			return ChunkAlloc(size, nobjs);
		}
		return result;
	}
};

//對類內部的靜態成員進行初始化
char *__DefaultAllocTemplate<false, 0>::_StartFree = NULL;
char *__DefaultAllocTemplate<false, 0>::_EndFree = NULL;
size_t __DefaultAllocTemplate<false, 0>::_HeapSize = 0;

typedef typename __DefaultAllocTemplate<false, 0>::Obj Obj;

Obj * volatile __DefaultAllocTemplate<false, 0> ::_FreeList[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凉城县| 铁岭市| 昌江| 辽中县| 嵩明县| 达尔| 山丹县| 名山县| 晋中市| 禄劝| 蓬安县| 郴州市| 普格县| 东至县| 丰都县| 顺义区| 桂林市| 丹寨县| 绥滨县| 潜江市| 肃北| 保定市| 桓台县| 山东| 九江市| 滨州市| 长沙县| 扶风县| 拉萨市| 贡觉县| 乡城县| 大埔县| 武宣县| 临清市| 漠河县| 吉木乃县| 阳高县| 台北县| 汶上县| 洞口县| 启东市|