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 全域性區資料區 全域性資料區劃分為三個區域。全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。常量資料存放在另乙個區域裡。這些資料在程式結...