一個程序本質上都是由 BSS 段、data段、text段三個組成的。可以看到一個可執行程序在存儲(沒有調入內存)時分為代碼段、數據區和未初始化數據區三部分。
- BSS段(未初始化數據區):在采用段式內存管理的架構中,BSS段(bss segment)通常是指用來存放程序中未初始化的全局變量的一塊內存區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態內存分配。
- 數據段:在采用段式內存管理的架構中,數據段(data segment)通常是指用來存放程序中已初始化的全局變量的一塊內存區域。數據段屬於靜態內存分配。
- 代碼段:在采用段式內存管理的架構中,代碼段(text segment)通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,並且內存區域屬於只讀。在代碼段中,也有可能包含一些只讀的常數變量,例如字符串常量等。
程序編譯后生成的目標文件至少含有這三個段,這三個段的大致結構圖如下所示:
text段和data段在編譯時已經分配了空間,而BSS段並不占用可執行文件的大小,它是由鏈接器來獲取內存的。
bss段(未進行初始化的數據)的內容並不存放在磁盤上的程序文件中。其原因是內核在程序開始運行前將它們設置為0。需要存放在程序文件中的只有正文段和初始化數據段。
data段(已經初始化的數據)則為數據分配空間,數據保存到目標文件中。
數據段包含經過初始化的全局變量以及它們的值。BSS段的大小從可執行文件中得到,然后鏈接器得到這個大小的內存塊,緊跟在數據段的后面。當這個內存進入程序的地址空間后全部清零。包含數據段和BSS段的整個區段此時通常稱為數據區。
可執行程序在運行時又多出兩個區域:棧區和堆區。
(4)棧區:由編譯器自動釋放,存放函數的參數值、局部變量等。每當一個函數被調用時,該函數的返回類型和一些調用的信息被存放到棧中。然后這個被調用的 函數再為他的自動變量和臨時變量在棧上分配空間。每調用一個函數一個新的棧就會被使用。棧區是從高地址位向低地址位增長的,是一塊連續的內存區域,最大容 量是由系統預先定義好的,申請的棧空間超過這個界限時會提示溢出,用戶能從棧中獲取的空間較小。
(5)堆區:用於動態分配內存,位於BSS和棧中間的地址區域。由程序員申請分配和釋放。堆是從低地址位向高地址位增長,采用鏈式存儲結構。頻繁的 malloc/free造成內存空間的不連續,產生碎片。當申請堆空間時庫函數是按照一定的算法搜索可用的足夠大的空間。因此堆的效率比棧要低的多。
下圖將體現c的源文件對應存儲空間:
此時程序還沒有被放入內存,只是在硬盤存儲的情況,此時bss並未占用空間。bss在鏈接的時候被獲得內存空間。
下圖表示程序運行,即程序在內存時的存儲布局:
//main.c int a = 0; //全局初始化區 char *p1; //全局未初始化區 main() { static int c =0; //全局(靜態)初始化區 int b; //棧 char s[] = "abc"; //棧 char *p2; //棧 char *p3 = "123456"; //"123456\0"在常量區,p3在棧上。 p1 = (char *)malloc(10); p2 = (char *)malloc(20); //分配得來得10和20字節的區域就在堆區。 }