1、內(nèi)存管理
我們需要知道——變量,其實(shí)是內(nèi)存地址的一個(gè)抽像名字罷了。在靜態(tài)編譯的程序中,所有的變量名都會(huì)在編譯時(shí)被轉(zhuǎn)成內(nèi)存地址。機(jī)器是不知道我們?nèi)〉拿值?,只知道地址?/p>
內(nèi)存的使用時(shí)程序設(shè)計(jì)中需要考慮的重要因素之一,這不僅由于系統(tǒng)內(nèi)存是有限的(尤其在嵌入式系統(tǒng)中),而且內(nèi)存分配也會(huì)直接影響到程序的效率。因此,我們要對(duì)C語(yǔ)言中的內(nèi)存管理,有個(gè)系統(tǒng)的了解。
在C語(yǔ)言中,定義了4個(gè)內(nèi)存區(qū)間:代碼區(qū);全局變量和靜態(tài)變量區(qū);局部變量區(qū)即棧區(qū);動(dòng)態(tài)存儲(chǔ)區(qū),即堆區(qū);具體如下:
1>棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。
2>堆區(qū)(heap)— 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表。
3>全局區(qū)(靜態(tài)區(qū))(static)—全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的 另一塊區(qū)域。 - 程序結(jié)束后由系統(tǒng)釋放。
4>常量區(qū)—常量字符串就是放在這里的。 程序結(jié)束后由系統(tǒng)釋放。
5>程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。我們來(lái)看張圖:
圖1
首先我們要知道,源代碼編譯成程序,程序是放在硬盤上的,而非內(nèi)存里!只有執(zhí)行時(shí)才會(huì)被調(diào)用到內(nèi)存中!我們來(lái)看看程序結(jié)構(gòu),ELF是是Linux的主要可執(zhí)行文件格式。ELF文件由4部分組成,分別是ELF頭(ELF header)、程序頭表(Program header table)、節(jié)(Section)和節(jié)頭表(Section header table)。具體如下:
1>Program header描述的是一個(gè)段在文件中的位置、大小以及它被放進(jìn)內(nèi)存后所在的位置和大小。即要加載的信息;
2>Sections保存著object 文件的信息,從連接角度看:包括指令,數(shù)據(jù),符號(hào)表,重定位信息等等。在圖中,我們可以看到Sections中包括:
text 文本結(jié) 存放指令;
rodata 數(shù)據(jù)結(jié) readonly;
data 數(shù)據(jù)結(jié) 可讀可寫;
3>Section頭表(section header table)包含了描述文件sections的信息。每個(gè)section在這個(gè)表中有一個(gè)入口;每個(gè)入口給出了該section的名字,大小,等等信息。相當(dāng)于 索引!
而程序被加載到內(nèi)存里面,又是如何分布的呢?我們看看上圖中:
1正文和初始化的數(shù)據(jù)和未初始化的數(shù)據(jù)就是我們所說(shuō)的數(shù)據(jù)段,正文即代碼段;
2>正文段上面是常量區(qū),常量區(qū)上面是全局變量和靜態(tài)變量區(qū),二者占據(jù)的就是初始化的數(shù)據(jù)和未初始化的數(shù)據(jù)那部分;
3>再上面就是堆,動(dòng)態(tài)存儲(chǔ)區(qū),這里是上增長(zhǎng);
4>堆上面是棧,存放的是局部變量,就是局部變量所在代碼塊執(zhí)行完畢后,這塊內(nèi)存會(huì)被釋放,這里棧區(qū)是下增長(zhǎng);
5>命令行參數(shù)就是001之類的,環(huán)境變量什么的前面的文章已經(jīng)講過(guò),有興趣的可以去看看。
我們知道,內(nèi)存分為動(dòng)態(tài)內(nèi)存和靜態(tài)內(nèi)存,我們先講靜態(tài)內(nèi)存。
1.1靜態(tài)內(nèi)存
存儲(chǔ)模型決定了一個(gè)變量的內(nèi)存分配方式和訪問(wèn)特性,在C語(yǔ)言中主要有三個(gè)維度來(lái)決定:存儲(chǔ)時(shí)期 、作用域 、鏈接。
1、存儲(chǔ)時(shí)期存儲(chǔ)時(shí)期:變量在內(nèi)存中的保留時(shí)間(生命周期)存儲(chǔ)時(shí)期分為兩種情況,關(guān)鍵是看變量在程序執(zhí)行過(guò)程中會(huì)不會(huì)被系統(tǒng)自動(dòng)回收掉。
1) 靜態(tài)存儲(chǔ)時(shí)期 Static在程序執(zhí)行過(guò)程中一旦分配就不會(huì)被自動(dòng)回收。通常來(lái)說(shuō),任何不在函數(shù)級(jí)別代碼塊內(nèi)定義的變量。無(wú)論是否在代碼塊內(nèi),只要采用static關(guān)鍵字修飾的變量。
2) 自動(dòng)存儲(chǔ)時(shí)期 Automatic除了靜態(tài)存儲(chǔ)以外的變量都是自動(dòng)存儲(chǔ)時(shí)期的,或者說(shuō)只要是在代碼塊內(nèi)定義的非static的變量,系統(tǒng)會(huì)肚臍自動(dòng)非配和釋放內(nèi)存;
2、作用域作用域:一個(gè)變量在定義該變量的自身文件中的可見(jiàn)性(訪問(wèn)或者引用)在C語(yǔ)言中,一共有3中作用域:1) 代碼塊作用域在代碼塊中定義的變量都具有該代碼的作用域。從這個(gè)變量定義地方開(kāi)始,到這個(gè)代碼塊結(jié)束,該變量是可見(jiàn)的;
2) 函數(shù)原型作用域出現(xiàn)在函數(shù)原型中的變量,都具有函數(shù)原型作用域,函數(shù)原型作用域從變量定義處一直到原型聲明的末尾。
3) 文件作用域一個(gè)在所有函數(shù)之外定義的變量具有文件作用域,具有文件作用域的變量從它的定義處到包含該定義的文件結(jié)尾處都是可見(jiàn)的;
3、鏈接鏈接:一個(gè)變量在組成程序的所有文件中的可見(jiàn)性(訪問(wèn)或者引用);C語(yǔ)言中一共有三種不同的鏈接:1) 外部鏈接如果一個(gè)變量在組成一個(gè)程序的所有文件中的任何位置都可以被訪問(wèn),則稱該變量支持外部鏈接;
2) 內(nèi)部鏈接如果一個(gè)變量只可以在定義其自身的文件中的任何位置被訪問(wèn),則稱該變量支持內(nèi)部鏈接。
3) 空鏈接如果一個(gè)變量只是被定義其自身的當(dāng)前代碼塊所私有,不能被程序的其他部分所訪問(wèn),則成該變量支持空鏈接
我們來(lái)看一個(gè)代碼示例:
#include
inta = 0;// 全局初始化區(qū)
char*p1;//全局未初始化區(qū)
intmain()
{
intb;//b在棧區(qū)
chars[] = "abc";//棧
char*p2; //p2在棧區(qū)
char*p3 = "123456";//123456 平博| 网上玩百家乐的玩法技巧和规则 | 金冠百家乐的玩法技巧和规则| 百家乐官网破解仪恒达| 大发888网页在线游戏| 风水罗盘24山| 万宁市| 粤港澳百家乐赌场娱乐网规则| 澳门百家乐官网然后赢| 大西洋娱乐城开户地址| 澳门百家乐十大缆| 百家乐官网西园出售| 皇冠现金网哪个最好| 百家乐筹码方| 百家乐官网国际娱乐场| 真人百家乐| 做生意的风水摆件| 永利高百家乐官网网址| 大发888娱乐城手机版| 百家乐输了100万| 澳门百家乐官网玩法心得技巧| 凯时百家乐技巧| 百家乐官网真人游戏网上投注 | 澳门百家乐官网介绍| bet365怎么存款| 百家乐怎样玩的| 云鼎百家乐官网的玩法技巧和规则 | gt百家乐平台| 哪里有百家乐官网游戏下载| 桑植县| 大发888娱乐场下载官方| 太阳百家乐3d博彩通| 百家乐官网娱乐网址| 宜春市| 大发888屡败屡战| 网络百家乐的陷阱| 在线百家乐官网下注| 百家乐官网如何打公式| 沈阳娱乐棋牌网| 潘多拉百家乐的玩法技巧和规则| 百家乐官网在线娱乐场|