通過乙個小例子來簡單理解C語言中的記憶體空間管理

2022-10-04 01:48:07 字數 3165 閱讀 6958

對於乙個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語言中的記憶體空間管理

本文位址: /ruanjian/c/135292.html

用乙個簡單的例子來理解python高階函式

用乙個簡單的例子來理解python高階函式 最近在用mailx傳送郵件,寫法大致如下.echo body mailx s title a corp.com,b corp.com 不知什麼原因,在一台機器上只要mailto中包含空格,郵件就傳送不出去.所以需要對收件人做規範化處理,即去除空格,去除多餘...

AAPCS 學習課後練習 通過乙個小例子來講解

一 有個函式有10個引數,請問是引數是如何傳遞的?請畫出壓棧圖 32位 64位 1 首先看arm32 編寫 test.c include int func int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,int v9,int p1 in...

乙個小例子對多型簡單的理解

class parent public void writeway class child extends parent public void writeway public class pc 乙個叫做張三的人,偽裝 比如貼上鬍子,看上去像自己父親的年齡 然後對外稱自己為張某某 成了自己的父親張某...