關於C/C++內存管理示例詳解

1、內存分配方式

在C++中,內存分成五個區,分別是堆、棧、自由存儲區、靜態存儲區和常量存儲區。

1) 棧

執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置處理器指令集中,效率很高,但分配的內存容量有限。

2) 堆

由new分配的內存塊,釋放由程序員控制。如果程序員沒有釋放,那麼就在程序結束的時候,被操作系統回收。

3) 自由存儲區

由malloc等分配的內存塊,用free結束自己的生命。

4) 靜態存儲區

全局變量和靜態變量被分配到同一塊內存中。C語言中,全局變量分為已初始化和未初始化。

5) 常量存儲區

裡面存放的是常量,不允許修改。 

2、堆和棧的區別

int * ptr = (int*)malloc(sizeof(int)*4);

在棧中存放瞭一個指向堆內存的指針ptr。在程序會先確定在堆中分配內存的大小,然後利用operator new分配內存,然後放回這塊內存的首地址,放在棧中。

1) 空間大小不同

在32位系統中,堆的空間是4G,而棧的空間很小。

2) 分配方式不同

堆是動態分配的,沒有靜態分配。棧的靜態分配時編譯器完成的,動態分配由alloca函數分配。棧的動態分配由編譯器進行釋放。

3) 管理方式不同

棧是由編譯器自動管理。堆的釋放是由程序員控制。

4) 生長方式不同

堆的生長方式是向上的,向著內存地址增加的方向。棧的生長方式是向下的,是向著內存地址減小的方向。

5) 能否產生碎片

對於堆,頻繁的new/delete會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。

6) 分配效率不同

棧是機器系統系統的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定棧的效率比較高。

堆是C/C++函數庫提供的,庫函數會按照一定的算法,在堆內存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於內存碎片太多),就有可能調用系統功能去增加程序數據段的內存空間,這樣就有機會分到足夠大小的內存,然後進行返回。

3、operator new和operator delete

3.1 為什麼要進行重載?

在嵌入式系統中,由於內存的限制,頻繁的動態分配不定大小的內存會引起很大的問題以及堆破碎的風險。

當你必須要使用new和delete的時候,你不得不控制C++中的內存分配。你需要用重載的全局new和delete代替系統的內存分配符。需要給類重載new和delete。

一個防止內存破碎的方法是從不同固定大小的內存池中分配不同類型的對象。對單個類重載new和delete,你就可以靈活的控制內存分配。

3.2 重載全局的new和delete操作符

void* operator new(size_t size)
{
	void* p = malloc(size);
	return (p);
}

void operator delete(void*p)
{
	free(p);
}

3.3 類重載new和delete

為單個類重載new和delete

class TestClass
{
public:
	void* operator new(size_t size)
	{
		void* p = malloc(size);
		return p;
	}
	void operator delete(void* p)
	{
		free(p);
	}
};

為單個類重載new[] 和 delete[]

class TestClass
{
public:
	void* operator new[](size_t size)
	{
		void* p = malloc(size);
		return p;
	}
	void* operator delete[](void* p)
	{
		free(p);
	}
}

int main()
{
	TestClass* p  = new TestClass[10];
	delete [] p; 
	return 0;
}

註意:new[] 中的個數參數是數組的大小加上額外的存儲對象數目的字節。考慮到內存分配機制的因素,盡量避免使用對象數組。

4、有瞭malloc/free為什麼還要new/delete

malloc和free是C/C++語言的標準庫函數,new / delete是C++ 的運算符。都用於申請動態內存和釋放內存。

malloc / free 無法滿足動態對象的要求。對象在創建的同時同時自動執行構造函數,對象消亡之前自動執行析構函數。即就是C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理和釋放內存工作的運算符delete。

內部數據類型的對象沒有析構和構造的過程,所以對於他們來說malloc / free和new / delete是等價的。

5、內存耗盡的三種解決方法

在申請動態內存時,找不到足夠大的內存塊,malloc和new將返回NULL指針。

1)判斷指針是否為NULL,如果是則使用 return 終止函數

2)判斷指針是否為NULL,如果是則使用 exit(1) 終止程序

3)為malloc和new 設置異常處理函數 。

總結

到此這篇關於C/C++內存管理的文章就介紹到這瞭,更多相關C/C++內存管理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: