內存分配方法與策略

在C語言中,內存被分成5個區,它們分別是堆、棧、自由存儲區、全局/靜態存儲區和常量存儲區。

堆:是那些由new分配的內存塊,它們的釋放編譯器不用管,由應用程序去控制,一般一個new就要對應一個delete。加入此程序員沒有釋放掉,那麼程序結束後,操作系統會自動回收。

棧:是那些由編譯器在需要的時候分配,在無須的時候自動清除的變量的存儲區。裏面的變量通常是局部變量、函數參數等。

自由存儲區:是那些由malloc等分配的內存塊,它和堆是十分相似,但是它是用free來結束自己的生命的。

全局/靜態存儲區:全局和靜態變量被分配到同一塊內存中,它們一起佔用同一塊內存區。

常量存儲區:這是一塊比較特別的存儲區,它們裏面存放的是常量,不允許修改。

重點來啦!!!!

堆和棧的區別:

void f() { int* p = new int[5]; }

這條短短的語句就包含了堆和棧,看到new,即分配了一塊堆內存;對於p呢,它分配的是一塊棧內存。因而,這條語句的意思是:在棧內存中存放了一個指向一塊堆內存的指針p。在程序會先確定在堆中分配內存的大小,然後調用operator new分配內存,然後返回這塊內存的首地址,放入棧中,它的彙編代碼如下:

00401028 push 14h
0040102A call operator new(00401060)
0040102F add esp,4
00401032 mov dword ptr[ebp-8],eax
00401035 mov eax,dword ptr[ebp-8]
00401038 mov dword ptr[ebp-4],eax

這裏,刪除p的操作不是delete p,而是delete [] p,這是爲了告訴編譯器,刪除的是一個數組,編譯器就會根據相應的信息去進行釋放內存的工作。

重中之重!!!

堆和棧的主要區別有以下幾點:

(1)管理方式不同

對於棧來講,是由編譯器自動管理;對於堆來說,釋放工作由程序員控制,容易產生內存泄露。

(2)空間大小

一般來講,在32位系統下,堆內存能夠達到4G的空間,從這個角度來看,堆內存幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的。

(3)能否產生碎片不同

對於堆來說,頻繁的new/delete勢必造成內存空間的不連接,從而造成大量的碎片,使程序效率降低。對於棧來說,則不會存在此問題,因爲棧是先進後出的,它們是一一對應的,以至於永遠都不可能有一個內存塊從棧中間跳出來。

(4)生長方向

對於堆來說,生長方向是向上的,即向着內存地址增加的方向;對於棧來講,它的生長方向是向下的,即向着內存地址減小的方向增長。

(5)分配方式

堆都是動態分配的,沒有靜態分配的堆。棧有兩種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,它的動態分配是由編譯器進行釋放,無須手工實現。

(6)分配效率

棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,入棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆的機制是很複雜的,例如,爲了分配一塊內存,庫函數會按照一定的算法在堆內存中搜索可用的足夠大小的空間,假如沒有足夠大小的空間,就有可能調用系統功能去增加程序數據段的內存空間,這樣就有機會分到足夠大小的內存,然後進行返回。顯然,堆的效率比棧要低得多。

總之:無論是堆還是棧,都要防止越界現象的產生,因爲越界的結果要麼是程序崩潰、要麼是摧毀程序的堆、棧結構,產生意想不到的結果。



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