【C++內存管理】內存管理實例 (二) —— Embeded pointer

上一篇的內存管理簡單實例中,我們用一個 next 指針將分配的一整塊內存中的每個對象大小的內存塊鏈接成鏈表,客戶端需要動態分配對象內存時,直接從鏈表上獲取,減少了不必要的 cookie 內存消耗。但是缺點也很明顯,就是增加了每個對象的 next 指針的內存消耗。我們可以看看什麼時候會使用到 next 指針:

  • 當分配了一大塊內存,這一大塊內存上的每個對象大小的小內存塊需要用 next 指針串在一起,注意,此時內存塊對於客戶端來說處於爲分配狀態,也就是客戶端並沒有使用這塊內存
  • 當客戶端使用 new 申請分配一塊內存時,將從事先分配好的內存鏈表上取出一小塊,分配給客戶端使用。注意,客戶端使用時,next 數組將不再被使用。
  • 當客戶端使用 delete 將對象內存回收時,這塊內存將會被再次插入到鏈表上。注意,此時又會重新使用 next 指針,串接到鏈表上。

以上的分析可以看出,當分配內存和回收內存的時候,纔會去使用到 next 指針,當該內存被分配給客戶端使用時,該 next 指針將不在被使用到。也就是說,對象本身的數據內存和 next 指針的數據內存不會同時被使用。因此,我們可以將對象本身的數據和 next 指針的數據共用同一個內存。於是就使用到了 union 數據類型。 這種類型的指針被稱爲 embeded pointer
看如下代碼:
class Airplane
{
private:
	struct AirplaneRep
	{
		unsigned long miles;
		char type;
	};

	union
	{
		AirplaneRep rep;	//針對使用中的 object,以 AirplaneRep 類型去解釋內存數據
		Airplane *next;		//針對 freelist 上的 object,以指針形式解釋內存數據
	};

public:
	unsigned long getMiles() { return rep.miles; }
	char getType() { return rep.type; }
	void set(unsigned long m, char t)
	{
		rep.miles = m;
		rep.type = t;
	}

	void* operator new(size_t size)
	{
		//如果大小有誤
		//在發生繼承時,可能會產生大小有誤的情況
		if (size != sizeof(Airplane))
			return ::operator new(size);

		Airplane* p = headOfFreeList;
		if (p)
		{
			headOfFreeList = headOfFreeList->next;
		}
		else
		{
			//申請分配一大塊新的內存
			Airplane *newBlock = static_cast<Airplane*>(::operator new(BLOCK_SIZE * size));
			//將每一小塊串成 free list
			//跳過第一塊小內存,因爲它將作爲本次的分配內存結果,沒有必要串在 list 上
			for (int i = 1; i < BLOCK_SIZE; ++i)
			{
				newBlock[i].next = &newBlock[i + 1];
			}
			//鏈表尾部置空
			newBlock[BLOCK_SIZE - 1].next = nullptr;
			//當前返回地址
			p = newBlock;
			headOfFreeList = &newBlock[1];
		}
		return p;
	}

	void operator delete(void* pDead, size_t size)
	{
		if (pDead == nullptr)
			return;
		if (size != sizeof(Airplane))
		{
			::operator delete(pDead);
			return;
		}

		Airplane* p = static_cast<Airplane*>(pDead);
		//插入到鏈表頭部
		p->next = headOfFreeList;
		headOfFreeList = p;
	}


private:
	static const int BLOCK_SIZE;
	//未使用內存塊鏈表頭指針
	static Airplane* headOfFreeList;
};

當內存被分配使用時,則用 AirplaneRep 及 Airplane 的數據類型去解釋;當內存未被分配使用時,則用 next 指針去解釋。
這樣的話,一個 Airplane 對象只佔用 8 個字節內存(內存對齊),next 指針並沒有多消耗內存。


Amazing~~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章