C語言記憶體機制詳解

2021-06-29 12:06:54 字數 3118 閱讀 5654

對於乙個c語言程式而言,記憶體空間主要由五個部分組成**段(.text)、資料段(.data)、bss段(.bss),堆和棧組成,其中**段,資料段和bss段是編譯的時候由編譯器分配的,而堆和

在上圖中,由編譯器分配的位址空間都是在連線的時候分配的,而執行時分配的空間是在程式執行時由系統分配的

bss段:bss段(bss segment)通常是指用來存放程式中未初始化的全域性變數和靜態變數 (這裡注意乙個問題:一般的書上都會說全域性變數和靜態變數是會自動初始化的,那麼哪來的未初始化的變數呢?變數的初始化可以分為顯示初始化和隱式初始化,全域性變數和靜態變數如果程式設計師自己不初始化的話的確也會被初始化,那就是不管什麼型別都初始化為0,這種沒有顯示初始化的就是我們這裡所說的未初始化。既然都是0那麼就沒必要把每個0都儲存起來,從而節省磁碟空間,這是bss的主要作用)的一塊記憶體區域。bss是英文block started by symbol的簡稱。bss段屬於靜態記憶體分配。 bss節不包含任何資料,只是簡單的維護開始和結束的位址,即總大小,以便記憶體區能在執行時分配並被有效地清零。bss節在應用程式的二進位制映象檔案中並不存在,即不占用磁碟空間 而只在執行的時候占用記憶體空間 ,所以如果全域性變數和靜態變數未初始化那麼其可執行檔案要小很多。

資料段:資料段(data segment)通常是指用來存放程式中已初始化的全域性變數和靜態變數的一塊記憶體區域。資料段屬於靜態記憶體分配,可以分為唯讀資料段和讀寫資料段。 字串常量等,但一般都是放在唯讀資料段中 。

**段:**段(code segment/text segment)通常是指用來存放程式執行**的一塊記憶體區域。這部分區域的大小在程式執行前就已經確定,並且記憶體區域通常屬於唯讀, 某些架構也允許**段為可寫,即允許修改程式。在**段中,也有可能包含一些唯讀的常數變數,例如字串常量等,但一般都是放在唯讀資料段中 。 

堆(heap):堆是用於存放程序執行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。當程序呼叫malloc等函式分配記憶體時,新分配的記憶體就被動態新增到堆上(堆被擴張);當利用free等函式釋放記憶體時,被釋放的記憶體從堆中被剔除(堆被縮減) 

棧 (stack):棧又稱堆疊, 是使用者存放程式臨時建立的區域性變數,也就是說我們函式括弧「{}」中定義的變數(但不包括static宣告的變數,static意味著在資料段中存放變 量)。除此以外,在函式被呼叫時,其引數也會被壓入發起呼叫的程序棧中,並且待到呼叫結束後,函式的返回值也會被存放回棧中。由於棧的先進先出特點,所以 棧特別方便用來儲存/恢復呼叫現場。從這個意義上講,我們可以把堆疊看成乙個寄存、交換臨時資料的記憶體區。注意:棧空間是向下增長的,每個執行緒有乙個自己的棧,在linux上預設的大小是8m,可以用ulimit檢視和修改。

棧系統提供的功能,特點是快速高效,缺點是有限制,資料不靈活;而堆是函式庫提供的功能,特點是靈活方便,資料適應面廣泛,但是效率有一定降低。

以下是乙個簡單的c檔案,環境是os--linux,arch--ppc

##sta.c###

#include

int kk[100] = ;

int tt[100];

int ii;

int main()

經過gcc -s sta.c之後,生成的彙編**如下

##sta.s###

.file   "sta.c"

.gnu_attribute 4, 2

.gnu_attribute 8, 3

.globl kk

.section        ".data"

.align 2

.type   kk, @object

.size   kk, 400

kk:.long   1

.long   2

.long   3

.long   4

.long   5

.zero   380

.lcomm  si.2254,4,4

.type   si.2254, @object

.section        .rodata

.align 2

.lc1:

.string "i is %d/n"

.align 2

.lc0:

.string "abcd"

.zero   5

.section        ".text"

.align 2

.globl main

.type   main, @function

main:

stwu 1,-32(1)

mflr 0

stw 0,36(1)

stw 31,28(1)

mr 31,1

lis 9,.lc0@ha

la 9,.lc0@l(9)

lwz 0,0(9)

lbz 9,4(9)

stw 0,12(31)

stb 9,16(31)

li 0,0

stb 0,17(31)

li 0,0

stb 0,18(31)

li 0,0

stb 0,19(31)

li 0,0

stb 0,20(31)

li 0,0

stb 0,21(31)

lis 9,.lc1@ha

la 3,.lc1@l(9)

crxor 6,6,6

bl printf

li 0,0

mr 3,0

lwz 11,0(1)

lwz 0,4(11)

mtlr 0

lwz 31,-4(11)

mr 1,11

blr.size   main, .-main

.comm   tt,400,4

.comm   ii,4,4

.ident  "gcc: (gnu) 4.2.3"

.section        .note.gnu-stack,"",@progbits

note: 一般編譯器和作業系統實現來說,對於虛擬位址空間的最低(從0開始的幾k)的一段空間是未被對映的,也就是說它在程序空間中,但沒有賦予實體地址,不能被訪問。這也就是對空指標的訪問會導致crash的原因 ,因為空指標的位址是0。至於為什麼預留的不是乙個位元組而是幾k,是因為記憶體是分頁的,至少要一頁;另外幾k的空間還可以用來捕捉使用空指標的情況。

另外推薦乙個部落格 寫得很好很全

C語言記憶體機制

最近有參加一些c c 類的面試,感覺筆試的題目大都偏重於考察基本原理,這對我來說是乙個不小的挑戰 平時學習的時候往往忽視了那些基本原理,急於動手去實踐,結果忽視了靈魂性的東西 今後的學習中,禁忌一味動手寫 要結合理論多思考,多問些為什麼,不然就真成為了 民工了,知其然,知其所以然,才能成為大師 關於...

詳解C語言記憶體對齊

在c語言裡有乙個機制是記憶體對齊,當然不止c語言,包括其他的程式語言都會有記憶體對齊機制,否則編譯出來的軟體無法正常執行,至於為什麼呢?眾所周知,在記憶體中,所有的資料都是按位元組為最小單位儲存的,儲存單位稱為儲存單元,所以也叫記憶體是由很多儲存單元組成的,這些儲存單元 位元組 都有固定的位址標示著...

c語言記憶體對齊詳解

一 什麼是位元組對齊,為什麼要對齊?現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。對齊的作...