程式執行時記憶體的各種資料段

2021-08-11 00:26:58 字數 2921 閱讀 5602

1.bss段

該段用來存放沒有被初始化或初始化為0的全域性變數,因為是全域性變數,所以在程式執行的整個生命週期內都存在於記憶體中。有趣的是這個段中的變數只占用程式執行時的記憶體空間,而不占用程式檔案的儲存空間。可以用以下程式來說明這點,檔名為bss.c

[cpp]

view plain

copy

#include 

intbss_data[1024 * 1024];  

intmain()    

這個程式非常簡單,定義乙個4m的全域性變數,然後返回。編譯成可執行檔案bss,並檢視可執行檔案的檔案屬性如圖2所示:

從可執行檔案的大小4774b可以看出,bss資料段(4m)並不占用程式檔案的儲存空間,在下面的data段中,我們可以看到data段的資料是占用可執行檔案的儲存空間的。

在圖1中,有檔名且屬性為rw-p的記憶體區間,就是bss段。

2.data段

初始化過的全域性變數資料段,該段用來儲存初始化了的非0的全域性變數,如果全域性變數初始化為0,則編譯有時會出於優化的考慮,將其放在bss段中。因為也是全域性變數,所以在程式執行的整個生命週期內都存在於記憶體中。與bss段不同的是,data段中的變數既佔程式執行時的記憶體空間,也佔程式檔案的儲存空間。可以用下面的程式來說明,檔名為data.c:

[cpp]

view plain

copy

#include 

intdata_data[1024 * 1024] = ;  

intmain()    

這個程式與上面的bss唯一的不同就是全域性變數int型陣列data_data,其中第0個元素的值初始化為1,其他元素的值初始化成預設的0,而因為陣列的位址是連續的,所以只要有乙個元素在data段中,則其他的元素也必然在data段中。編

譯連線成可執行檔案data,並檢視可執行檔案的檔案屬性如圖3所示:

從可執行檔案的大小來看,data段資料(data_data陣列的大小,4m)占用程式檔案的儲存空間。

在圖1中,有檔名且屬性為rw-p的記憶體區間,就是data段,它與bss段在記憶體中是共用一段記憶體的,不同的是,bss段資料不占用檔案,而data段資料占用檔案儲存空間。

3.rodata段

該段是常量資料段,用於存放常量資料,ro就是read only之意。但是注意並不是所有的常量都是放在常量資料段的,其特殊情況如下:

1)有些立即數與指令編譯在一起直接放在**段(text段,下面會講到)中。

2)對於字串常量,編譯器會去掉重複的常量,讓程式的每個字串常量只有乙份。

3)有些系統中rodata段是多個程序共享的,目的是為了提高空間的利用率。

在圖1中,有檔名的屬性為r--p的記憶體區間就是rodata段。可見他是受保護的,只能被讀取,從而提高程式的穩定性。

4.text段

text段就是**段,用來存放程式的**(如函式)和部分整數常量。它與rodata段的主要不同是,text段是可以執行的,而且不被不同的程序共享。

在圖1中,有檔名且屬性為r-xp的記憶體區間就是text段。就如我們所知道的那樣,**段是不能被寫的。

5.stack段

該段就是棧段,用來儲存臨時變數和函式引數。程式中的函式呼叫就是以棧的方式來實現的,通常棧是向下(即向低位址)增長的,當向棧中push乙個元素,棧頂指標就會向低位址移動,當從棧中pop乙個元素,棧頂指標就會向高位址移動。棧中的資料只在當前函式或下一層函式中有效,當函式返回時,這些資料自動被釋放,如果繼續對這些資料進行訪問,將發生未知的錯誤。通常我們在程式中定義的不是用malloc系統函式或new出來的變數,都是存放在棧中的。例如,如下函式:

[cpp]

view plain

copy

void

func()    

整型變數a,整型指標變數n_ptr和char型指標變數c_ptr,都存放在棧段中,而n_ptr和c_ptr指向的變數,由於是malloc或new出來的,所以存放在堆中。當函式func返回時,a、n_ptr、c_ptr都會被釋放,但是n_ptr和c_ptr指向的記憶體卻不會釋放。因為它們是存在於堆中的資料。

在圖1中,檔名為stack的記憶體區間即為棧段。

6.heap段

heap(堆)是最自由的一種記憶體,它完全由程式來負責記憶體的管理,包括什麼時候申請,什麼時候釋放,而且對它的使用也沒有什麼大小的限制。在c/c++中,用alloc系統函式和new申請的記憶體都存在於heap段中。

以上面的程式為例,它向堆申請了乙個int和乙個char的記憶體,因為沒有呼叫free或delete,所以當函式返回時,堆中的int和char變數並沒有釋放,造成了記憶體洩漏。

由於在圖1所對應的**中沒有使用alloc系統函式或new來申請記憶體,所以heap段並沒有在圖1中顯示出來,所以以下面的程式來說明heap段的位置,**檔案為heap.c,**如下:

[cpp]

view plain

copy

#include 

#include 

#include 

intmain()    

檢視其執行時記憶體空間分布如下:

可以看到檔名為heap的記憶體區間就是heap段。從上圖,也可以看出,雖然我們只申請4個位元組(sizeof(int))的空間,但是在作業系統中,記憶體是以頁的方式進行管理的,所以在分配heap記憶體時,還是一次分配就為我們分配了乙個頁的記憶體。注:無論是圖1,還是上圖,都有一些沒有檔名的記憶體區間,其實沒用檔名的記憶體區間表示使用mmap對映的匿名空間。

程式執行時記憶體的各種資料段

1.簡介 在linux系統中,程式在記憶體中的分布如下所示 text 段,部分是編譯後程式的主體,也就是程式的機器指令。儲存函式的位址。bss段 bss segment 通常是指用來存放程式中未初始化的全域性變數的一塊記憶體區域。bss段屬於靜態記憶體分配。因為是全域性變數,所以在程式執行的整個生命...

程式執行時的記憶體

當乙個源 通過gcc編譯成a.out,執行a.out時 程式便開始了執行之旅 即程序 作業系統為程序分配堆疊空間,隨後把程式執行碼放入文字段,把程式經過初始化的全域性變數和靜態變數放入data 把程式為初始化的全域性變數和靜態變數放入bss段 並對bss段資料初始化為0 之後cpu 段指標指向mai...

程式執行時記憶體管理

1,管理執行階段記憶體空間分配 malloc new int pn new int 儲存的型別,記憶體根據此設定相應儲存位元組的記憶體 pn是記憶體位址 所以 當宣告乙個變數的指標變數時沒初始化,宣告後再來初始化則pn 接收的應該是變數在記憶體中的位址 variablename pn是儲存在記憶體的...