天天看點

java基礎Haep(堆)和Stack(棧)差別

簡單的可以了解為:

heap:是由malloc之類函數配置設定的空間所在地。位址是由低向高增長的。 

stack:是自動配置設定變量,以及函數調用的時候所使用的一些空間。位址是由高向低減少的。

注:何為高位址,何為低位址呢?(以32位系統為例)

就是存儲的時候越靠近0xfffffffff那麼位址就越高,越靠近0x000000,位址也就越低,如下圖所示:

首先我們要知道我們c程式映像中記憶體的空間布局情況:在《c專家程式設計》中或者《unix環境進階程式設計》中有關于記憶體空間布局情況的說明,大緻如下圖:

----------------------- 最高記憶體位址 0xffffffff

 | 棧底

 .

 .              棧

  棧頂

-----------------------

 |

\|/

null (空洞)

/|\

                堆

未初始化的資料

----------------(統稱資料段)

初始化的資料

正文段(代碼段)

----------------------- 最低記憶體位址 0x00000000

接下來我們需要了解幾個重要的概念:

1、棧區(stack)— 由編譯器自動配置設定釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似于資料結構中的棧。 

2、堆區(heap) — 一般由程式員配置設定釋放, 若程式員不釋放,程式結束時可能由os回收 。注意它與資料結構中的堆是兩回事,配置設定方式倒是類似于鍊             表,呵呵。 

     3、全局區(靜态區)(static)—,全局變量和靜态變量的存儲是放在一塊的,初始化的全局變量和靜态變量在一塊區域, 未初始化的全局變量和未初始化           的靜态變量在相鄰的另一塊區域。 - 程式結束後有系統釋放 

     4、文字常量區 —常量字元串就是放在這裡的。 程式結束後由系統釋放 

     5、程式代碼區—存放函數體的二進制代碼。 

堆和棧的一些理論知識:

stack(棧): 

由系統自動配置設定。 例如,聲明在函數中一個局部變量 int b; 系統自動在棧中為b開辟空間 

     heap(堆): 

需要程式員自己申請,并指明大小,在c中malloc函數 。

申請後系統的響應 

棧:隻要棧的剩餘空間大于所申請空間,系統将為程式提供記憶體,否則将報異常提示棧溢出。 

堆:首先應該知道作業系統有一個記錄空閑記憶體位址的連結清單,當系統收到程式的申請時, 

會周遊該連結清單,尋找第一個空間大于所申請空間的堆結點,然後将該結點從空閑結點連結清單中删除,并将該結點的空間配置設定給程式,另外,對于大多數系統,會在這塊記憶體空間中的首位址處記錄本次配置設定的大小,這樣,代碼中的delete語句才能正确的釋放本記憶體空間。另外,由于找到的堆結點的大小不一定正好等于申請的大小,系統會自動的将多餘的那部分重新放入空閑連結清單中。 

     申請大小的限制 

棧:在windows下,棧是向低位址擴充的資料結構,是一塊連續的記憶體的區域。這句話的意思是棧頂的位址和棧的最大容量是系統預先規定好的,在 windows下,棧的大小是2m(也有的說是1m,總之是一個編譯時就确定的常數),如果申請的空間超過棧的剩餘空間時,将提示overflow。是以,能從棧獲得的空間較小。 

堆:堆是向高位址擴充的資料結構,是不連續的記憶體區域。這是由于系統是用連結清單來存儲的空閑記憶體位址的,自然是不連續的,而連結清單的周遊方向是由低位址向高位址。堆的大小受限于計算機系統中有效的虛拟記憶體。由此可見,堆獲得的空間比較靈活,也比較大。

     申請效率的比較: 

棧由系統自動配置設定,速度較快。但程式員是無法控制的。 

堆是由new配置設定的記憶體,一般速度比較慢,而且容易産生記憶體碎片,不過用起來最友善. 

另外,在windows下,最好的方式是用virtualalloc配置設定記憶體,他不是在堆,也不是在棧是直接在程序的位址空間中保留一快記憶體,雖然用起來最不友善。但是速度, 也最靈活 

     堆和棧中的存儲内容 

棧: 在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的位址,然後是函數的各個參數,在大多數的c編譯器中,參數是由右往左入棧的,然後是函數中的局部變量。注意靜态變量是不入棧的。 

當本次函數調用結束後,局部變量先出棧,然後是參數,最後棧頂指針指向最開始存的位址,也就是主函數中的下一條指令,程式由該點繼續運作。 

堆:一般是在堆的頭部用一個位元組存放堆的大小。堆中的具體内容有程式員安排。