C程式記憶體分配 Linux程式設計

2021-05-22 17:28:31 字數 3851 閱讀 5659

3.1.1 c程式記憶體分配

1.c 程式結構

下面列出 c 語言可執行程式的基本情況(linux 2.6 環境/gcc4.0)。

[root@localhost ctest]# ls test -l //test 為乙個可執行程式

-rwxr-xr-x 1 root root 4868 mar 26 08:10 test

[root@localhost ctest]# file test //此檔案基本情況

test: elf 32-bit lsb executable, intel 80386, version 1 (sysv), for gnu/linux 2.2.5,

dynamically linked (uses shared libs), not stripped

[root@localhost ctest]# size test //此二進位制可執行檔案結構情況

//**區 靜態資料/全域性初始化資料區 未初始化資料區 十進位制總和 十六進製制總和 檔名

text data bss dec hex filename

906 284 4 1194 4aa test

可以看出,此可執行程式在存 儲時(沒有調入到記憶體)分為**區(text)、數 據區( data)

和未初始化資料區(bss)3 個部分。

(1)**區 (text segment)。存放 cpu 執行的機器指令(machine instructions)。通常,

**區是可共享的(即另外的 執行程式可以呼叫它),因為對於頻繁被執行的程式,只需要在

記憶體中有乙份**即可。**區通常是唯讀的,使其唯讀的原因是防止程式意外地修改了它

的 指令。另外,**區還規劃了區域性變數的相關資訊。

(2)全域性初始化資料區/靜態資料區(initialized data segment/data segment)。該區包含了

在程式中明確被初始化的全域性變數、靜態變數(包括全域性靜態變數和區域性靜態變數)和常量

數 據(如字串常量)。例如,乙個不在任何函式內的宣告(全域性資料):

int maxcount = 99;

使得變數 maxcount 根據其初始值被儲存到初始化資料區中。

static mincount=100;

這宣告了乙個靜態資料,如果是在 任何函式體外宣告,則表示其為乙個全域性靜態變數,

如果在函式體內(區域性),則表示其為乙個區域性靜態變數。另外,如果在函式名前加上 static,

則表示此函式只能在當前檔案中被呼叫。

(3)未初始化資料區。亦稱 bss 區(uninitialized data segment),存入的是全域性未初始化

變數。bss 這個叫法是根據乙個早期的彙編運算子而來,這個彙編運算子標誌著乙個塊的開

始。 bss 區的資料在程式開始執行之前被核心初始化為 0 或者空指標(null)。例如乙個不

在任何函式內的宣告:

long sum[1000];

將變數 sum儲存到未初始化資料區。

圖 3-1 所示為可執行**儲存時結構和執行時結構的對照圖。乙個正在執行著的 c 編譯程式

占用的記憶體分為**區、初始化資料區、未初始化資料區、堆區和 棧區 5 個部分。

可執行**

(**區)

已初始化全域性變數、靜態變數

和常量資料(資料區)

堆區(向上增長)

棧區(向 下增長)

未初始化全域性變數

(bss區,用零初始化)

可執行**

(**區)

已初始化全域性變數、靜態變數

和 常量資料(資料區)

未初始化變數

(bss區,用零初始化)

高位址低位址

儲存時三個區域

(用size查 看)

執行時的五

個區域儲存時的 3 個區域

(用 size 檢視)

執行時的 5 個區域

圖 3-1 c 程式的記憶體布局

(1)**區(text segment)。**區指令根據程式設計流程依次執行,對於順序指令,

則 只會執行一次(每個程序),如果反覆,則需要使用跳轉指令,如果進行遞迴,則需要借助

棧來實現。

**區的指令中包括操作碼和要操作的對 象(或物件位址引用)。如果是立即數(即具體

的數值,如 5),將直接包含在**中;如果是區域性資料,將在棧區分配空間,然後引用該數

據 位址;如果是 bss 區和資料區,在**中同樣將引用該資料位址。

(2)全域性初始化資料區/靜態資料區(data segment)。只初始化一次。

(3)未初始化資料區(bss)。在執行時改變其值。

(4) 棧區(stack)。由編譯器自動分配釋放,存放函式的引數值、區域性變數的值等。其

操作方式類似於資料結構中的棧。每當乙個函式被呼叫,該函式返 回位址和一些關於呼叫的

資訊,比如某些暫存器的內容,被儲存到棧區。然後這個被呼叫的函式再為它的自動變數和

臨時變數在棧區上分配空間, 這就是 c 實現函式遞迴呼叫的方法。每執行一次遞迴函式呼叫,

乙個新的棧框架就會被使用,這樣這個新例項棧裡的變數就不會和該函式的另乙個例項 棧裡

面的變數混淆。

(5)堆區(heap)。用於動態記憶體分配。堆在記憶體中位於 bss 區和棧區之間。一般由程式

員分配和釋 放,若程式設計師不釋放,程式結束時有可能由 os **。

之所以分成這麼多個區域,主要基於以下考慮:

l 乙個程序在執行過程中,**是根據流程依次執行的,只需要訪問一次,當然跳轉

和遞迴有可能使**執行多次,而資料一般都需要訪問多次,因此單獨開 闢空間以

方便訪問和節約空間。

l 臨時資料及需要再次使用的**在執行時放入棧區中,生命周期短。

l 全域性資料和靜態資料有可能在整個程式執行過程中都需要訪問,因此單獨儲存管理。

l 堆區由使用者自由分配,以便管理。

下面通過一段簡單 的**來檢視 c 程式執行時的記憶體分配情況。相關資料在執行時的位

置如注釋所述。 //main.cpp

int a = 0; //a 在全域性已初始化資料區

char *p1; //p1 在 bss 區(未初始化全域性變數)

main()

2.記憶體分配方式

在 c 語言中,物件可以使用靜態或動態的方式分配記憶體空間。

l 靜態分配:編譯器在處理程式源**時分配。

l 動態分配:程式在執行時呼叫 malloc 庫函式申請分配。

靜態記憶體分配是在程式執行之前進行的因而效率比較高,而動態記憶體分配則可以靈活的

處理未知數目的。

靜 態與動態記憶體分配的主要區別如下:

l 靜態物件是有名字的變數,可以直接對其進行操作;動態物件是沒有名字的變數,

需要通過指標間接地 對它進行操作。

l 靜態物件的分配與釋放由編譯器自動處理;動態物件的分配與釋放必須由程式設計師

顯式地管理,它通過 malloc()和 free 兩個函式(c++中為 new 和 delete 運算子)來

完成。

以下是採用靜態分配方式的例子。

int a=100;

此行**指示編譯器分配足夠的儲存區以存放乙個整型值,該儲存區與名字 a 相關聯,

並用數值 100 初始化該儲存區。

以下是採用動態分配方式的例子。

p1 = (char *)malloc(10*sizeof(int)); //分配得來得 10*4 位元組的區域在堆區

此行**分配了 10 個 int 型別的物件,然後返回物件在記憶體中的位址,接著這個位址被

用來初始化指 針對象 p1,對於動態分配的記憶體唯一的訪問方式是通過指標間接地訪問,其釋

放方法為:

free(p1);

c 程式記憶體分配

乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os 注意它與資料結構中的堆是兩回事,分配方式倒是類...

C程式記憶體分配

在任何程式設計環境及語言中,記憶體管理都十分重要。在目前的計算機系統或嵌入式系統中,記憶體資源仍然是有限的。因此在程式設計中,有效地管理記憶體資源是程式設計師首先考慮的問題。第1節主要介紹記憶體管理基本概念,重點介紹c程式中記憶體的分配,以及c語言編譯後的可執行程式的儲存結構和執行結構,同時還介紹了...

C程式記憶體分配

從作業系統的角度簡單介紹一下程序。程序是占有資源的最小單位,這個資源當然包括記憶體。在現代作業系統中,每個程序所能訪問的記憶體是互相獨立的 一些交換區除外 而程序中的執行緒所以共享程序所分配的記憶體空間。在作業系統的角度來看,程序 程式 資料 pcb 程序控制塊 區 text 用來存放cpu執行的機...