tft每日頭條

 > 生活

 > c語言内存管理和使用

c語言内存管理和使用

生活 更新时间:2024-12-02 10:26:31
一,内存模型

在C語言中,内存可分用五個部分:

  • 1. BSS段(Block Started by Symbol): 用來存放程序中未初始化的全局變量的内存區域。
  • 2. 數據段(data segment): 用來存放程序中已初始化的全局變量的内存區域。
  • 3. 代碼段(text segment): 用來存放程序執行代碼的内存區域。
  • 4. 堆(heap):用來存放進程運行中被動态分配的内存段,它的大小并不固定,可動态擴張或縮減。當進程調用malloc分配内存時,新分配的内存就被動态添加到堆上,當進程調用free釋放内存時,會從堆中剔除。
  • 5. 棧(stack):存放程序中的局部變量(但不包括static聲明的變量,static變量放在數據段中)。同時,在函數被調用時,棧用來傳遞參數和返回值。由于棧先進先出特點。所以棧特别方便用來保存/恢複調用現場。

c語言内存管理和使用(一文搞懂C語言内存模型與棧)1

嵌入式進階教程分門别類整理好了,看的時候十分方便,由于内容較多,這裡就截取一部分圖吧。

c語言内存管理和使用(一文搞懂C語言内存模型與棧)2

需要的朋友私信【内核】即可領取

如下往上,分别是text段,data段,BSS段,堆,棧

c語言内存管理和使用(一文搞懂C語言内存模型與棧)3

由上圖可知:

0x0000 0000:保留區域, 最底層

  • 代碼區:用來存放程序代碼和常量,隻讀(運行期會一直存在)
  • 常量區:一般常量,字符常量,隻讀(運行期會一直存在)
  • 全局數據區:全局變量和靜态變量,可讀寫(運行期會一直存在)
  • 堆段:malloc/free的内存,malloc時分配,free時釋放(向上增長)

未分配堆内存

0x4000 0000:動态鍊接庫

未分配棧内存

棧段:局部變量,函數調用參數返回值(向上增長)

0xc000 0000 ~ 0xffff ffff:内核空間(1G)

二,棧詳解

棧(stack): 是由系統自動分配和釋放,存放函數的參數值,返回值,局部變量等。其操作方式類似于數據結構中的棧。

2.1棧的申請

1. 當在函數或塊内部聲明一個局部變量時,如:int nTmp; 系統會判斷申請的空間是否足夠,足夠,在棧中開辟空間,提供内存;不夠空間,報異常提示棧溢出。

2. 當調用一個函數時,系統會自動為參數當局部變量,壓進棧中,當函數調用結束時,會自動提升堆棧。(可查看彙編中的函數調用機制)

2.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];

2.3棧的生長方向

棧的生長方向和存放數據的方向相反,自頂向下

2.4 棧分配例子

int function( int var1 ,int var2) {undefined int var3; int var4; }

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

0xc000 0000

var1

0xc000 0000 - 4

var2

0xc000 0000 - 8

var3

0xc000 0000 - 12

var4

三,堆詳解

堆(heap):是用來存放動态申請或釋放的區域。需要程序員分配和釋放,系統不會自動管理,如果用完不釋放,将會造成内存洩露,直到進程結速後,系統自動回收。

3.1 堆的目的

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

3.2申請和釋放

int function() {undefined char *pTmp = (char*) malloc(1024); // malloc在堆中分配1024字節空間 //pTmp 為局部變量,隻占四字節 free(pTmp); // free為手動釋放堆中空間 pTmp = NULL; // 防止pTmp變野指針誤用 }

3.3堆的大小

堆是可以申請大塊内存的區域,但堆的大小到底有多大,下面分析下,以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); // 理論上

3.4 堆的生長方向

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

3.5 堆的注意事項

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

1. 釋放問題:分配了堆内存,一定要記得手動釋放,否則将會導緻内存洩露

void* alloc(int size) {undefined char* ptr = (char*)malloc(size); return ptr; }

上面函數如果外部調用,沒有釋放,将内存不會釋放造成洩露。

2. 碎片問題:如果頻繁地調用内存分配和釋放,将會使堆内存造成很多内存碎片,從而造成空間浪費和效率低下。

a) 對于比較固定,或可預測大小的,可以程序啟動時,即分配好空間,如:某個對象不會超過500個,那個可先生成,object *ptr = (object*)malloc(object_size*500);

b) 結構對齊,盡量使結構不浪費内存

3. 超堆大小問題:如果申請内存超過堆大小,會出現虛拟内存不足等問題

a) 盡量不要申請很大的内存,如直需要,可采用内存數據庫等

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

char * pTmp = (char*)malloc(102400); if(pTmp == 0) // 一定在記得判斷 {undefined return false; }

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

free(pTmp); pTmp = NULL; // 防止變野指針

6. 多次釋放問題:如果第5并沒置NULL,多次釋放将會出現問題。

四,例子

nt 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() {undefined char l_var[1024]; // 棧 g_ptr = (char*)malloc(1024); // mall内存 椎中 static int g_int =1; // data 段中 }

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved