C語言 記憶體分配 詳細解說

2021-08-09 20:18:37 字數 3430 閱讀 3777

要想完全理解c語言的記憶體分配,必須要知道計算機的組成和基本原理。

1. 計算機的組成

計算機的五大組成部分:運算器、控制器、儲存器、輸入裝置和輸出裝置。

我們都知道計算機的處理中心是cpu,它主要由運算器和控制器組成。

1.運算器

實現算術運算和邏輯運算的部分,主要對資料進行加工處理。

2.控制器

計算機的指揮中心,它通過位址訪問儲存器,從儲存器中取出指令(程式),並指出下一指令在儲存器中的位置,將取出的指令經指令暫存器送往指令解碼器,經過對指令的分析產生相應的操作,控制其他部件的有條不紊的工作。

程式計數器(pc) pc暫存器中的內容是,下一條要取的指令的16位單元儲存位址。當執行一條指令時,首先需要根據pc中存放的指令位址,將指令由記憶體取到指令暫存器中,此過程稱為「取指令」。與此同時,pc中的位址或自動加1或由轉移指標給出下一條指令的位址。如此迴圈,執行每一條指令。

指令暫存器(ir) 存放當前要執行的指令

指令解碼器(id)對現行指令進行分析,確定指令型別、指令所要完成的操作以及定址方式

時序產生器 用於產生時序脈衝和節拍電位去控制計算機的有序工作

狀態/條件暫存器 用於儲存指令執行完成後產生的條件碼。例如:運算是否溢位,結果是正是負,是否有進製等。而且還儲存中斷和系統工作狀態等資訊。

微操作訊號發生器 把指令提供的操作訊號、時序產生器提供的時序訊號以及由控制功能部件反饋的狀態訊號等綜合成特定的操作序列,從而完成取指令的執行控制。

3.儲存器

計算機存放所有資料和程式的記憶部分,它分為兩大類:一類是內部儲存器(記憶體),一類是外部儲存器(外存)。儲存器由若干個儲存單元組成,每個儲存單元都有乙個位址,計算機通過位址對儲存單元進行讀寫。

4.輸入裝置

向計算機輸入資訊(程式、資料、聲音、文字、圖形、影象等)的裝置(鍵盤、滑鼠、圖形掃瞄器、觸控螢幕、條形碼輸入器、光筆等)。

5.輸出裝置

主要有顯示器、印表機和繪圖儀等。

2. 記憶體分配

在任何程式設計環境及語言中,記憶體管理都十分重要。在目前的計算機系統或嵌入式系統中,記憶體資源仍然是有限的。因此在程式設計中,有效地管理記憶體資源是程式設計師首先考慮的問題

1. c程式結構:可執行**儲存時

下面是c語言可執行程式的基本情況:

上面分別是:

我們可以看出程式在未執行前,沒有調入到記憶體時,分為三個部分:**區(text)、資料區(data)、未初始化資料區(bss)。

1.**區(text)

存放cpu可執行的機器指令,由於程式被經常使用,防止其被意外修改,**區通常是唯讀的。

2.全域性初始化資料區/靜態資料區(data)

存放被初始化的全域性變數、靜態變數(全域性靜態變數和區域性靜態變數)、常量資料(如字串常量)。

3.未初始化資料區(bss)

存放未初始化的全域性變數,bss這個叫法是根據早期的彙編運算子而來的,這個彙編運算子標誌著乙個塊的開始。bss區的資料在程式開始執行之前被核心初始化為0或空指標(null)。

2.c程式結構:程式執行時

乙個正在執行的c程式,是經過編譯、連線後形成的二進位制映像檔案。其占用的記憶體分為4個段區域:

程式執行時記憶體區域如下圖:

1. **區

存放函式體的二進位制**。

指令根據程式設計流程依次執行,對於順序指令,則只會執行一次,如果反覆,則需使用跳轉指令,如果進行遞迴,則需借助棧來實現。

**區包括操作碼和要操作的物件(或物件的位址引用),如果是立即數(即具體的數值,如2),將直接包含在**中;如果是區域性資料,將在棧中分配空間,然後引用該資料的位址;如果是bss區和資料區,在**中同樣引用該資料的位址。

2. 資料段

全域性初始化資料區/靜態資料區,只初始化一次。

上面已經說過,在程式編譯時,該區域已經被分配好了,這塊內存在程式的整個執行期間都存在,當程式結束時,才會被釋放。

1. 已初始化的讀寫資料段:

已初始化資料是在程式中宣告,並且具有初值的變數,這些變數需要占用儲存器的空間,

在程式執行時它們需要位於可讀寫的記憶體區域內,並且有初值,以供程式執行時讀寫。

在程式中一般為已經初始化的全域性變數,已經初始化的靜態區域性變數(static修飾的已經初始化的變數)

2. 唯讀資料段是程式使用的一些不會被更改的資料,使用這些資料的方式類似查表式的操作,

由於這些變數不需要更改,因此只需要放置在唯讀儲存器中即可。

一般是const修飾的變數以及程式中使用的文字常量一般會存放在唯讀資料段中。

在執行時改變其值。

未初始化資料是在程式中宣告,但是沒有初始化的變數,這些變數在程式執行之前不需要占用儲存器的空間。與讀寫資料段類似,它也屬於靜態資料區。但是該段中資料沒有經過初始化。未初始化資料段只有在執行的初始化階段才會產生,因此它的大小不會影響目標檔案的大小。在程式中一般是沒有初始化的全域性變數和沒有初始化的靜態區域性變數。

3. 棧區(stack)

存放函式的引數值和區域性變數,由編譯器自動分配釋放,其操作方式類似於資料結構的棧。其特點是不需要程式設計師去考慮記憶體管理的問題,很方便;同時棧的容量很有限,在linux系統中,棧的容量只有8m,並且當相應的範圍結束時(如函式),區域性變數就不能再使用。

4. 堆區(heap)

有些操作物件只有在程式執行時才能確定,這樣編譯器在編譯時就無法為他們預先分配空間,只有程式執行時才分配,這就是動態記憶體分配。堆區就是用於動態記憶體分配(如malloc的動態記憶體分配),堆在記憶體中位於bss區和棧區之間,一般由程式設計師申請和釋放。

之所以分配如此多的區域,主要是因為:

乙個程序在執行時,**是根據流程依次執行的,**只需訪問一次,當然跳轉或遞迴時**會被執行多次,而資料一般都需要訪問多次,因此單獨開闢空間以便訪問和節約空間。

下面是乙個詳細的**,來全面分析記憶體分配情況:

main.c

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

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

static int c = 0; //c在全域性初始化資料區(c是全域性靜態變數)

struct employee

e1; //e1在全域性初始化資料區

int main()

s1; //s1在棧區

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

p2 = (char*)malloc(20); //分配得來的20個位元組的區域在堆區

name = (cahr *)malloc(20); //分配得來的20個位元組的區域在堆區

/*從常量區的「hello world」字串複製到剛分配到的堆區*/

strcpy(p1, 「hello world」);

free(p1); //釋放記憶體

free(p2); //釋放記憶體

}

關於堆疊之間的區別參考:堆疊之間的區別

常量相關,未完待續。

C語言記憶體分配

c語言的記憶體分配主要有5個區域 1 棧區 在執行函式時,函式內的區域性變數 不包括static變數 函式返回值的儲存單元在棧區上建立。函式執行結束時這些儲存單元自動被釋放。棧區記憶體分配運算內置於處理器的指令集中,效率很高,但分配的記憶體容量有限。2 堆區 程式在執行的時候用malloc call...

C語言記憶體分配

c語言的記憶體分配主要有5個區域 1 棧區 在執行函式時,函式內的區域性變數 不包括static變數 函式返回值的儲存單元在棧區上建立。函式執行結束時這些儲存單元自動被釋放。棧區記憶體分配運算內置於處理器的指令集中,效率很高,但分配的記憶體容量有限。2 堆區 程式在執行的時候用malloc call...

C語言記憶體分配

objective c從名字來看就可以知道是一門超c語言,所以了解c語言的記憶體模型對於理解objective c的記憶體管理有很大的幫助。c語言記憶體模型圖如下 從圖中可以看出記憶體被分成了5個區,每個區儲存的內容如下 棧區在什麼時候釋放記憶體呢?我們通過下面的乙個例子來說明下 void prin...