1. 程式人生 > >內存的使用:棧區、堆區、靜態區、只讀區

內存的使用:棧區、堆區、靜態區、只讀區

效率 空間 綜述 安排 cnblogs 變量 註意 調用 內存地址

內存的使用感覺好亂啊,需要整理一下!於是參考C++ primer與網上資源,整理如下:

一、綜述:內存中的棧區分配的是局部變量空間;堆區是向上增長的用於分配程序員申請的內存空間(比如new 申請的動態內存),註意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表;靜態區(全局區)是分配靜態變量,全局變量空間的初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域,程序結束後由系統釋放;只讀區是分配常量和程序代碼空間的;對於常量,在實際情況中,是會復用的,比如變量a和b都賦值為”abc”則實際上他們指向同一塊地址。舉例子說明一下,如下:

 1     int
a = 0; //全局初始化區 2  char *p1; //全局未初始化區 3  int main() 4 { 5   int b; // 6   char s[] = "abc"; // 7   char *p2; // 8   char *p3 = "123456"; //123456\0在常量區,p3在棧上。 9   static int c =0;     //全局(靜態)初始化區 10   p1 = (char *)malloc(10); // 11   p2 = (char *)malloc
(20); //註意p1、p2本身是在棧中的。
12 p1= "123456"; //123456\0在常量區,編譯器將p1與p3所指向“123456\0”優化成同一個地方。
14 }                

二、堆和棧的區別:

堆和棧的第一個區別就是申請方式不同:棧(英文名稱是stack)是系統自動分配空間的,例如我們定義一個 char a;系統會自動在棧上為其開辟空間。而堆(英文名稱是heap)則是程序員根據需要自己申請的空間,例如malloc(10);開辟十個字節的空間。由於棧上的空間是自動分配自動回收的,所以棧上的數據的生存周期只是在函數的運行過程中,運行後就釋放掉,不可以再訪問。而堆上的數據只要程序員不釋放空間,就一直可以訪問到,不過缺點是一旦忘記釋放,在程序運行過程中會造成內存泄露,只能等待程序結束時由系統回收。

三、申請內存後系統的響應:

棧:只要棧的剩余空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。

堆:首先應該知道操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閑結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的 delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多余的那部分重新放入空閑鏈表中。也就是說堆會在申請後還要做一些後續的工作這就會引出申請效率的問題 。

四、申請效率的比較:

棧由系統自動分配,速度較快。但程序員是無法控制的。堆是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.。

使用棧就象我們去飯館裏吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。

使用堆就象是自己動手做喜歡吃的菜肴,比較慢,但是比較符合自己的口味,而且自由度大。

五、申請大小的比較:

棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。

堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。一般來講在32位系統下,堆內存可以達到4G的空間。由此可見,堆獲得的空間比較靈活,也比較大。

六、堆和棧中的存儲內容:

棧: 在函數調用時,第一個進棧的是主函數中函數調用後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然後是函數中的局部變量。註意靜態變量是不入棧的。當本次函數調用結束後,局部變量先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。

堆:一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。

附:全局變量、局部變量、靜態全局變量、靜態局部變量的區別:

生存周期不同、作用範圍不同、、分配方式不同;

全局變量具有全局作用域。全局變量只需在一個源文件中定義,就可以作用於所有的源文件。當然,其他不包含全局變量定義的源文件需要用extern 關鍵字再次聲明這個全局變量。

局部變量也只有局部作用域,它是自動對象(auto),它在程序運行期間不是一直存在,而是只在函數執行期間存在,函數的一次調用執行結束後,變量被撤銷,其所占用的內存也被收回。

靜態局部變量具有局部作用域,它只被初始化一次,自從第一次被初始化直到程序運行結束都一直存在,它和全局變量的區別在於全局變量對所有的函數都是可見的,而靜態局部變量只對定義自己的函數體始終可見。

靜態全局變量也具有全局作用域,它與全局變量的區別在於如果程序包含多個文件的話,它作用於定義它的文件裏,不能作用到其它文件裏,即被static關鍵字修飾過的變量具有文件作用域。這樣即使兩個不同的源文件都定義了相同名字的靜態全局變量,它們也是不同的變量。

從分配內存空間看:全局變量,靜態局部變量,靜態全局變量都在靜態存儲區分配空間,而局部變量在棧裏分配空間。

從以上分析可以看出, 把局部變量改變為靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜態變量後是改變了它的作用域,限制了它的使用範圍。因此static 這個說明符在不同的地方所起的作用是不同的。

網上資源參考:https://www.cnblogs.com/xiaowenhui/p/4669684.html

內存的使用:棧區、堆區、靜態區、只讀區