在C語言中,内存可分用五個部分:
嵌入式進階教程分門别類整理好了,看的時候十分方便,由于内容較多,這裡就截取一部分圖吧。
需要的朋友私信【内核】即可領取
如下往上,分别是text段,data段,BSS段,堆,棧
由上圖可知:
0x0000 0000:保留區域, 最底層
未分配堆内存
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. 對于局部變量,盡量不定義大的變量,如大數組(大于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變野指針誤用
}
堆是可以申請大塊内存的區域,但堆的大小到底有多大,下面分析下,以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.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每日頭條,我们将持续为您更新最新资讯!