【C++內存管理】內存管理實例 (一 ) —— 簡單形式

內存管理無外乎希望提高兩方面性能:

  • 提高運行效率。可以通過減少 malloc 函數調用的次數來提高運行效率。
  • 提高空間利用率。減少浪費。每次通過 new 分配的內存塊上下兩個部分都帶有 cookie,記錄着這塊內存的大小等相關信息。可以通過分配一大塊內存池,在將其中分爲一小塊一小塊以供對象實例存放,這樣的話,只在這一大塊的頭尾存在 cookie,中間部分省掉了很多 cookie 的佔用內存,提高空間利用率。

下面是一個簡單的內存管理的例子:
class Screen
{
public:
	Screen(int x) : i(x) {}
	int get() { return i; }

	void* operator new(size_t size)
	{
		Screen* p;

		//第一次時,分配一大塊內存
		if (!freeStore)
		{
			//需要分配的內存大小
			size_t chunk = screenChunk * size;

			//分配一塊內存,reinterpret_cast 將 char* 轉型爲 screen*
			freeStore = reinterpret_cast<Screen*>(new char[chunk]);
			p = freeStore;

			//將這一塊內存串成鏈表
			for (; p != &freeStore[screenChunk - 1]; ++p)
			{
				p->next = p + 1;
			}
			p->next = nullptr;
		}

		//保存當前內存塊地址
		p = freeStore;

		//指向下一塊內存
		freeStore = freeStore->next;
		return p;
	}

	void operator delete(void* pdead)
	{
		//直接將釋放的內存插入到鏈表頭部
		static_cast<Screen*>(pdead)->next = freeStore;
		freeStore = static_cast<Screen*>(pdead);
	}

private:
	Screen *next;

	//指向當前可用的待分配內存
	static Screen* freeStore;

	//一次分配的內存池的大小
	static const int screenChunk;

private:
	int i;
};

const int Screen::screenChunk = 24;
Screen* Screen::freeStore = nullptr;


int main()
{
	cout << sizeof(Screen) << endl;

	const int N = 10;
	Screen* p[N];
	for (int i = 0; i < N; ++i)
		p[i] = new Screen(i);

	for (int i = 0; i < N; ++i)
		cout << p[i] << endl;

	for (int i = 0; i < N; ++i)
		delete p[i];

}

輸出結果如下:
在這裏插入圖片描述
可以看到,每個 screen 指針都間隔 8 個字節,剛好等於 screen 的大小,證明 object 都在內存池中確實是緊密的排列在一起。


如果採用全局的 operator new ,輸出的結果如下:
在這裏插入圖片描述
分配的內存地址不連續。(由於每一塊內存中都包含 cookie 數據)


注意,由於爲了將內存池中的內存串成鏈表,Screen 類中新增了一個指針數據,這個數據的增加反過來又增加了內存消耗。所以,應該權衡這一個內存消耗和由於 cookie 數據的減少而節省下的來的內存。
總的來說,這種內存管理方式由於新增的指針的存在,所以它的設計並不算好,只是一個初步的方案。後面的改進方案可以消除這一個指針。

有幾個疑問說一說:
1.是最多隻能分配 screenChunk 個實例內存嗎?
並不是,screenChunk 只是每次新分配時的內存單元大小。分配的內存單元被串成鏈表,鏈表的尾部指向 null。當客戶端申請的實例動態內存個數超過 screenChunk 時,freeStore 再一次變成空指針,於是會再次申請新的內存。

2.那多次分配的內存單元豈不是互相獨立,沒有鏈接在一起了?
也並不是。各個分配的內存單元會在 operator delete 函數中被串起來。因爲每次客戶端歸還內存時,該小塊內存會被插入到當前頭指針 freeStore 的前面,由此實現鏈接。


接下來的這篇會將如何利用 Embeded pointer 的概念消除 next 指針佔用的內存。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章