C語言記憶體模型詳解

2021-08-18 19:14:16 字數 4085 閱讀 6431

second60  20180415

在c語言中,記憶體可分用五個部分:

1. bss段(

block started by symbol):

用來存放程式中未初始化的全域性變數的記憶體區域。

2. 資料段(data segment): 用來存放程式中已初始化的全域性變數的記憶體區域。

3. **段(text segment): 用來存放程式執行**的記憶體區域。

4. 堆(heap):用來存放程序執行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。當程序呼叫

malloc

分配記憶體時,新分配的記憶體就被動態新增到堆上,當程序呼叫

free

釋放記憶體時,會從堆中剔除。

5. 棧(stack):存放程式中的區域性變數(但不包括

static

宣告的變數,

static

變數放在資料段中)。同時,在函式被呼叫時,棧用來傳遞引數和返回值。由於棧先進先出特點。所以棧特別方便用來儲存

/恢復呼叫現場。

apue中的乙個典型

c記憶體空間分布圖

如下往上,分別是text段,

data

段,bss

段,堆,棧

由上圖可知:

0x0000 0000:保留區域

, 最底層

**區:用來存放程式**和常量,唯讀(執行期會一直存在

)常量區:一般常量,字元常量,唯讀(執行期會一直存在

)全域性資料區:全域性變數和靜態變數,可讀寫(執行期會一直存在

)堆段:malloc/free的記憶體,

malloc

時分配,

free

時釋放(

向上增長

)未分配堆記憶體

0x4000 0000:動態鏈結庫

未分配棧記憶體

棧段:區域性變數,函式呼叫引數返回值(向上增長

)0xc000 0000 ~ 0xffff ffff:核心空間

(1g)

棧(stack): 是由系統自動分配和釋放,存放函式的引數值,返回值,區域性變數等。其操作方式類似於資料結構中的棧。

1. 當在函式或塊內部宣告乙個區域性變數時,如:

int  ntmp;

系統會判斷申請的空間是否足夠,足夠,在棧中開闢空間,提供記憶體;不夠空間,報異常提示棧溢位。

2. 當呼叫乙個函式時,系統會自動為引數當區域性變數,壓進棧中,當函式呼叫結束時,會自動提公升堆疊。(可檢視彙編中的函式呼叫機制)

棧是有一定大小的,通常情況下,棧只有2m,不同系統棧的大小可能不同。

在linux中,檢視程序

/執行緒棧大小,命令:  

ulimit  -s

$  ulimit  -s

$  8192

我的系統中棧大小為 8192, 有些系統為

10240,

具體檢視自已系統棧大小

設定棧大小:

1. 臨時改變棧大小:

ulimit  -s  10240

2. 開機設定棧大小:在

/etc/rc.local

中加入

ulimit  -s  10240

3. 改變棧大小: 在

/etc/security/limits.conf

中加入* soft stack 10240

所以,在宣告區域性變數時,新手要特別注意棧的大小:

1. 對於區域性變數,盡量不定義大的變數,如大陣列(大於

2*1024*1024

位元組)char  buf[2*1024*1024]; // 可能會導致棧溢位

2. 對於記憶體較大或不知大小的變數,用堆分配,區域性變數用指標,注意要釋放

char*  pbuf = (char*)malloc(2*1024*1024); // char* 為區域性變數  

malloc

的內存在堆

free(pbuf);

3. 或定義在全域性區中,static變數 或常量區中

static  char  buf[2*1024*1024];

棧的生長方向和存放資料的方向相反,自頂向下

int  function( int  var1 ,int  var2)

var1,var2,var3在棧中的圖如下

:0xc000 0000

var1

0xc000 0000 - 4

var2

0xc000 0000 - 8

var3

0xc000 0000 - 12

var4

堆(heap)

:是用來存放動態申請或釋放的區域。需要程式設計師分配和釋放,系統不會自動管理,如果用完不釋放,將會造成記憶體洩露,直到程序結速後,系統自動**。

為什麼在堆呢?原因很簡單,在棧中,大小是有限制的,能常大小為2m,如果需要更大的空間,那麼就要用到堆了,堆的目的就是為了分配使用更大的空間。

int  function()

堆是可以申請大塊記憶體的區域,但堆的大小到底有多大,下面分析下,以32位系統為例。

在linux中,堆區的記憶體申請,在

32位系統中,理論上:

2^32=4g

,但如上面的記憶體分布圖可知:核心占用

1g空間。

0xffff ffff

1g核心空間

0xc000 0000

0xbfff fff

3g使用者空間(包

text

段,data

段,bss

段,堆,棧

)0x0000 0000

如上所知,理論上,使用malloc最大能夠申請空間大約

3g。但這是理論值,因為實際中,還會包含**區,全域性變數區和棧區。

char  *buf = (char*) malloc(3gb);   // 理論上

如上面的圖可知,堆是由低位址向高位址生長的

堆雖然可以分配較大的空間,但有一些要注意的地方,否則會出現問題。

1. 釋放問題:分配了堆記憶體,一定要記得手動釋放,否則將會導致記憶體洩露

void*  alloc(int size)

上面函式如果外部呼叫,沒有釋放,將記憶體不會釋放造成洩露

2. 碎片問題:如果頻繁地呼叫記憶體分配和釋放,將會使堆記憶體造成很多記憶體碎片,從而造成空間浪費和效率低下。

a) 對於比較固定,或可**大小的,可以程式啟動時,即分配好空間,如:某個物件不會超過500個,那個可先生成,

object *ptr = (object*)malloc(object_size*500);

b) 結構對齊,盡量使結構不浪費記憶體

3. 超堆大小問題:如果申請記憶體超過堆大小,會出現虛擬記憶體不足等問題

a) 盡量不要申請很大的記憶體,如直需要,可採用記憶體資料庫等

4. 分配是否成功問題:申請記憶體後,都在判斷記憶體是否分配成功,分配成功後才能使用,否則會出現段錯誤

char *  ptmp = (char*)malloc(102400);

if(ptmp == 0)   // 一定在記得判斷

5. 釋放後野指標問題:釋放指標後,一定要記得把指標的值設定成null,防止指標被釋放後誤用

free(ptmp);

ptmp = null; // 防止變野指標

6. 多次釋放問題:如果第5並沒置

null

,多次釋放將會出現問題。

int  g_var = 0; // data段

int  g_var1;  // bss 段

char g_str;    // bss 段

char g_str = 「hello world」; // g_str data段

, hello world

字段常量區

char* g_ptr = null; // data段

int test()

複習下c語言記憶體模型,網上雖然有很大記憶體模型的介紹,但是比較零散,本文詳細地介紹了其中的細節,當然也有不完善的地方,歡迎補充。

C語言記憶體模型

bss段 bss segment 通常是指用來存放程式中未初始化的全域性變數的一塊記憶體區域。bss是英文block started by symbol的簡稱。bss段屬於靜態記憶體分配。資料段 data segment 通常是指用來存放程式中 已初始化 的 全域性變數 的一塊記憶體區域。資料段屬於...

c語言記憶體模型

文章一 c語言的記憶體分配模型 1 程式 區 存放函式體的二進位制 2 全域性區資料區 全域性資料區劃分為三個區域。全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。常量資料存放在另乙個區域裡。這些資料在程式結...

c語言記憶體模型

文章一 c語言的記憶體分配模型 1 程式 區 存放函式體的二進位制 2 全域性區資料區 全域性資料區劃分為三個區域。全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。常量資料存放在另乙個區域裡。這些資料在程式結...