天天看點

C++中的堆和棧

在C++中,記憶體分為5個區:堆、棧、自由存儲區、靜态存儲區(或全局存儲區)和常量存儲區。

堆和棧都是C++的記憶體存儲區之一,下面介紹堆和棧對比用法:

1.管理方式和配置設定效率:

棧是機器系統提供的資料結構,是FILO(First In Last Out)結構,計算機底層對它進行了支援,棧的記憶體配置設定内置于處理器的指令集(配置設定了專門的寄存器存放棧的位址,壓棧和出棧都有專門的指令),這也就決定了棧的配置設定效率較高。

堆是由C/C++函數庫提供的,由一套複雜的算法實作。堆中有一個記錄空閑記憶體位址的連結清單,當系統收到程序的空間申請時,根據使用的配置設定算法找到合适的位址空間。(比如first-fit算法:周遊此連結清單,找到第一個空間大于申請大小的空閑記憶體配置設定給程序,從空閑連結清單中将此節點删除,并記錄此次配置設定的大小,添加到已配置設定記憶體連結清單中,另外将多餘的空閑空間添加到空閑連結清單中,将配置設定記憶體的首位址傳回給程序使用)此後程序可以合理地使用這塊空間,有時由于申請的空間太大,空閑連結清單中找不到合适的記憶體,系統會使用mmap擴充有效堆記憶體,以獲得更多的虛拟位址空間。基于以上,堆的申請效率較低。

2.空間特點:

棧的空間較小,windows下棧的大小是一個在編譯時就确定的常量,通常是1M或2M,在unbutu下一般是8M,Centos下是10M,可以通過ulimit -a檢視,ulimit -s進行修改。

棧是一塊連續的空間,每次申請也是申請連續的大小。

堆的空間較大,一般和系統有關,32位系統堆大小一般為4G。

堆是由空閑記憶體位址連結清單管理,堆空間是不連續的申請,每次申請都是在空閑空間連結清單上找合适大小的空閑空間進行配置設定。

3.記憶體碎片:

由于棧是系統進行配置設定和釋放,而且由于棧這種資料結構的特點FILO,不會出現間隔的配置設定,是以棧不會有産生記憶體碎片,而堆是由程式員手動進行配置設定和釋放,存在碎片。

4.配置設定方式:

棧是由系統配置設定和釋放,當申請的空間小于剩餘的空間則進行配置設定,否則抛出stack overflow。

棧有2種配置設定方式:靜态配置設定和動态配置設定。靜态配置設定是編譯器完成的,比如局部變量的配置設定。動态配置設定由alloca函數進行配置設定(alloca不具可移植性, 而且在沒有傳統堆棧的機器上很難實作),用完由編譯器自動釋放,如果手動釋放會出錯。

alloca

的函數具體用法:

頭檔案: malloc.h

函數原型:void * __cdecl alloca(size_t);

#include <stdio.h>
#include <malloc.h>
int main()
{	
	int *p = (int *)alloca(sizeof(int)*10);
	free(p); //error,空間在棧中,手動釋放是報錯
	return 0;
}
           

堆是由程式員自己進行申請和釋放,使用new和malloc等申請,對應的由delete和free進行釋放。使用靈活,但容易發生記憶體洩露(memory leak)申請的空間可以很大。在項目很大時,難免發生記憶體洩露。較好的選擇是重載new和delete,跟蹤定位程式發生記憶體洩露的地方。

5.生長方向:

棧的生長方向是向下生長,即由記憶體高位址向低位址生長。

堆的生長方向是向上生長,由記憶體的低位址向高位址生長。

堆和棧之間由一層臨界區,大小可以進行修改,如果棧的空間到達臨界區,則會提示stack overflow。

繼續閱讀