【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~~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章