轉自: http://book.51cto.com/art/200811/96138.htm程序員
C語言編譯後的可執行程序的存儲結構和運行結構數組
可執行程序在存儲時(沒有調入到內存)分爲代碼區(text)、數據區(data)和未初始化數據區(bss)3個部分。數據結構
(1)代碼區(text segment)。存放CPU執行的機器指令(machine instructions)。一般,代碼區是可共享的(即另外的執行程序能夠調用它),由於對於頻繁被執行的程序,只須要在內存中有一份代碼便可。代碼區一般是隻讀的,使其只讀的緣由是防止程序意外地修改了它的指令。另外,代碼區還規劃了局部變量的相關信息。框架
//text segment ----- CPU machine instructions;特色:共享、只讀、規劃了局部變量的相關信息。函數
(2)全局初始化數據區/靜態數據區(initialized data segment/data segment)。該區包含了在程序中明確被初始化的全局變量、靜態變量(包括全局靜態變量和局部靜態變量)和常量數據(如字符串常量)。例如,一個不在任何函數內的聲明(全局數據):spa
int maxcount = 99; 設計
使得變量maxcount根據其初始值被存儲到初始化數據區中。指針
static mincount=100;
這聲明瞭一個靜態數據,若是是在任何函數體外聲明,則表示其爲一個全局靜態變量,若是在函數體內(局部),則表示其爲一個局部靜態變量。另外,若是在函數名前加上static,則表示此函數只能在當前文件中被調用。code
(3)未初始化數據區。亦稱BSS區(uninitialized data segment),存入的是全局未初始化變量。BSS(block started symbol-由符號開始的塊)這個叫法是根據一個早期的彙編運算符而來,這個彙編運算符標誌着一個塊的開始。BSS區的數據在程序開始執行以前被內核初始化爲0或者空指針(NULL)。例如一個不在任何函數內的聲明:htm
long sum[1000];
將變量sum存儲到未初始化數據區。
下圖所示爲可執行代碼存儲時結構和運行時結構的對照圖。
一個正在運行着的C編譯程序佔用的內存分爲代碼區、初始化數據區、未初始化數據區、堆區和棧區5個部分。
程序運行期間,佔用內存空間分爲6段:
代碼段,只讀數據段(常量,字面值,const聲明的變量),已初始化可讀寫數據段(已初始化靜態和全局變量),未初始化可讀寫數據段(未初始化靜態和全局變量),堆,棧。
(1)代碼區(text segment)。代碼區指令根據程序設計流程依次執行,對於順序指令,則只會執行一次(每一個進程),若是反覆,則須要使用跳轉指令,若是進行遞歸,則須要藉助棧來實現。
代碼區的指令中包括操做碼和要操做的對象(或對象地址引用)。若是是當即數(即具體的數值,如5),將直接包含在代碼中;若是是局部數據,將在棧區分配空間,而後引用該數據地址;若是是BSS區和數據區,在代碼中一樣將引用該數據地址。
(2)全局初始化數據區/靜態數據區(Data Segment)。只初始化一次。
(3)未初始化數據區(BSS)。在運行時改變其值。
(4)棧區(stack)。由編譯器自動分配釋放,存放函數的參數值、局部變量的值等。其操做方式相似於數據結構中的棧。每當一個函數被調用,該函數返回地址和一些關於調用的信息,好比某些寄存器的內容,被存儲到棧區。而後這個被調用的函數再爲它的自動變量和臨時變量在棧區上分配空間,這就是C實現函數遞歸調用的方法。每執行一次遞歸函數調用,一個新的棧框架就會被使用,這樣這個新實例棧裏的變量就不會和該函數的另外一個實例棧裏面的變量混淆。
(5)堆區(heap)。用於動態內存分配。堆在內存中位於bss區和棧區之間。通常由程序員分配和釋放,若程序員不釋放,程序結束時有可能由OS回收。
之因此分紅這麼多個區域,主要基於如下考慮:
一個進程在運行過程當中,代碼是根據流程依次執行的,只須要訪問一次,固然跳轉和遞歸有可能使代碼執行屢次,而數據通常都須要訪問屢次,所以單獨開闢空間以方便訪問和節約空間。
臨時數據及須要再次使用的代碼在運行時放入棧區中,生命週期短。
全局數據和靜態數據有可能在整個程序執行過程當中都須要訪問,所以單獨存儲管理。
堆區由用戶自由分配,以便管理。
下面經過一段簡單的代碼來查看C程序執行時的內存分配狀況。相關數據在運行時的位置如註釋所述。
//main.cpp int a = 0; //a在全局已初始化數據區 char *p1; //p1在BSS區(未初始化全局變量) main() { int b; //b在棧區 char s[] = "abc"; //s爲數組變量,存儲在棧區, //"abc"爲字符串常量,存儲在已初始化數據區 char *p1,p2; //p一、p2在棧區 char *p3 = "123456"; //123456\0在已初始化數據區,p3在棧區 static int c =0; //C爲全局(靜態)數據,存在於已初始化數據區 //另外,靜態數據會自動初始化 p1 = (char *)malloc(10);//分配得來的10個字節的區域在堆區 p2 = (char *)malloc(20);//分配得來的20個字節的區域在堆區 free(p1); free(p2); }