網上找了一堆資料學習一下,了解這些,
有助於規化程序結構,優化代碼;
使用gcc編譯出來的程序,用size可以查看程序結構和大小,
如
1: #size hello
2: Text data bss dec hex filename
3: 778 200 4 982 3D6 hello
所以一個可執行的程序文件,結構分三部分:
.text 代碼段,用來存放代碼,一般是只讀的區域;
.data 數據段,用來存放全局初始化變量,常量,以及全局或局部靜態變量,只初始化一次;
.bss BSS段,用來存放全局未初化數據,用0初始化;
那有人問非全局變量放哪里了?
還有常說的堆和棧呢?
程序在執行時,會產生臨時變量或是函數返回值,
還有函數中動態分配的地址空間,如malloc, new等…
根據這些需求,才需要堆和棧的出現,
所以堆(heap)和棧(Stack)這兩個段是在程序運行時才有.
.stack 棧區,用來存放局部變量,函數的參數,返回值等,由編譯器自動分配釋放;
棧的概念來自數據結構,棧只能在一端操作,所以先入棧的后出,“先進后出”,這種結構保護之前的現場,
如一個函數被調用后,產生的臨時變量都會存到棧區的頂部,當函數完成后,會自動從頂部將剛使用的數據銷毀;
另外棧區的地址是從高地址向下增長的;
.heap 堆區,用來動態內存分配,如malloc, new申請的內存,由程序員分配釋放;
程序中不釋放,則程序結束時,由OS回收;據說這個和數據結構中的堆 沒有什么關系;堆區使用時地址向上增長;
以上5部分在內存的位置如下圖,
執行過程:
代碼區的指令依次執行,代碼由操作碼和操作數組成,操作碼決定是順序執行,還是跳轉,還是循環等;操作數可能是立即數,即具體的數直接包含在代碼中,或者是局部變量,則在棧區分配空間,然后引用該數據地址執行,或者是BSS,DATA段的數據,同樣引用其地址執行;
正因為代碼有不同的操作,所以程序在內存中執行時,才分成不同的區,以便節約空間或訪問方便;對於全局變量和靜態變量,一般不會更改其值,但整個執行過程都需要訪問,就單獨放到一個區進行管理;臨時變量生命周期短,需要頻繁的操作,則統一放到棧區;用戶自由分配使用的空間統一放在堆區,便於管理;
引用網上的例子,
1: //main.cpp
2: int a = 0; //a在全局已初始化數據區.data
3: char *p1; //p1在.bss(未初始化全局變量)
4: main()
5: {
6: int b; //b在棧區 .stack
7: char s[] = "abc"; //s為數組變量,存儲在棧區,.heap
8: //"abc"為字符串常量,存儲在已初始化數據區
9: char *p1,p2; //p1,p2在棧區
10: char *p3 = "123456"; //123456\0在已初始化數據區,p3在棧區
11: static int c =0; //C為全局(靜態)數據,存在於已初始化數據區
12: //另外,靜態數據會自動初始化
13: p1 = (char *)malloc(10);//分配得來的10個字節的區域在堆區
14: p2 = (char *)malloc(20);//分配得來的20個字節的區域在堆區
15: //注意p1,p2是局部變量,所以存儲在棧中,10Byte空間在堆中;
16: free(p1);
17: free(p2);
18: }
19:
以下引用這個博客的,堆和棧的區別:
http://www.cnblogs.com/hfww/archive/2011/06/04/2223366.html
二、堆和棧的理論知識
2.1申請方式
stack:
由系統自動分配。 例如,聲明在函數中一個局部變量 int b; 系統自動在棧中為b開辟空間
heap:
需要程序員自己申請,並指明大小,在c中malloc函數
如p1 = (char *)malloc(10);
在C++中用new運算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在棧中的。
2.2
申請后系統的響應
棧:只要棧的剩余空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。
堆:首先應該知道操作系統有一個記錄空閑內存地址的鏈表,當系統收到程序的申請時,
會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然后將該結點從空閑結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統, 會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等 於申請的大小,系統會自動的將多余的那部分重新放入空閑鏈表中。
2.3申請大小的限制
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩余空間時,將提示overflow。因 此,能從棧獲得的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。
2.4申請效率的比較:
棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行。堆則是C函數庫提供的,它的機制很復雜,例如為了分配一塊內存,庫函數會按照一定的算法(具體的算法可以參考數據結構/操作系統)在堆內存中搜索可用的足夠大的空間,如果沒有足夠大的空間(可能是由於內存碎片太多),就有需要操作系統來重新整理內存空間,這樣就有機會分到足夠大小的內存,然后返回。顯然,堆的效率比棧要低得多。
棧由系統自動分配,速度較快。但程序員是無法控制的。
堆是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是在棧是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。但是速度快,也最靈活。
另外...VS下更改棧大小的方法,
http://www.cnblogs.com/sosi/archive/2011/03/27/1997180.html