一.首先講解一下程序中的數(shù)據(jù)在內(nèi)存中的存放方式有以下幾種:
1.棧(也可以成為堆棧)區(qū):由編譯器自動(dòng)分配并且釋放,該區(qū)域一般存放函數(shù)的參數(shù)值殿衰,局部變量值等,當(dāng)函數(shù)運(yùn)行結(jié)束并且返回時(shí)承绸,所有的函數(shù)參數(shù)和局部變量都會(huì)被操作系統(tǒng)自動(dòng)回收枯怖。
2.堆區(qū):一般由程序員分配及釋放,若程序員不釋放萍桌,程序結(jié)束時(shí)可能由操作系統(tǒng)自動(dòng)回收宵溅。
3.寄存器區(qū):用來(lái)保存棧頂指針和指令指針
4.全局(靜態(tài))區(qū):全局變量和靜態(tài)變量是存儲(chǔ)在一塊的。初始化的全局變量和靜態(tài)變量在一塊區(qū)域梗夸,未初始化的全局變量和靜態(tài)變量在相鄰的另一塊區(qū)域层玲。程序結(jié)束后由系統(tǒng)釋放。
5.文字常量區(qū):存放常量字符串反症,程序結(jié)束后由系統(tǒng)釋放辛块。
6.程序代碼區(qū):存放函數(shù)體的二進(jìn)制代碼。
二铅碍、棧和堆的不同點(diǎn)
棧 | 堆 | |
---|---|---|
內(nèi)存申請(qǐng)和釋放方式上的不同 | 由系統(tǒng)自動(dòng)分配润绵,例如聲明一個(gè)局部變量int a;那么系統(tǒng)就會(huì)自動(dòng)在棧中為變量a開辟內(nèi)存空間胞谈,函數(shù)結(jié)束時(shí)變量a占的空間會(huì)被系統(tǒng)自動(dòng)回收 | 需要程序員自己申請(qǐng)尘盼,因此也需要指明變量大小。例如使用new操作符申請(qǐng):int *a=new int烦绳;那么系統(tǒng)就會(huì)在堆區(qū)分配一個(gè)大小為4Byte的內(nèi)存空間卿捎。使用delete操作符釋放:delete a;這樣就釋放了在堆區(qū)分配的空間 |
系統(tǒng)響應(yīng)的不同 | 只有在棧的空間大于申請(qǐng)的空間径密,系統(tǒng)才會(huì)為程序提供內(nèi)存午阵,否則將會(huì)提示overflow,也就是棧溢出(申請(qǐng)空間大于椣砣樱空間)
|
操作系統(tǒng)中有一個(gè)記錄空閑內(nèi)存地址的鏈表底桂,當(dāng)我們?cè)诙焉仙暾?qǐng)空間后,將在空閑鏈表中找到符合申請(qǐng)大小的空間節(jié)點(diǎn)惧眠,該節(jié)點(diǎn)會(huì)被系統(tǒng)從鏈表中刪除籽懦,然后分配給程序符合大小的內(nèi)存空間,多余的空間會(huì)回收到空閑鏈表中氛魁。如果不停地申請(qǐng)空間確沒有使用delete釋放暮顺,會(huì)造成內(nèi)存不停的增長(zhǎng)厅篓,這就是所謂的內(nèi)存泄漏(由于程序員的失誤,沒有對(duì)在堆區(qū)申請(qǐng)的內(nèi)存進(jìn)行釋放)
|
空間大小的不同 | 在windows下拖云,棧是一塊連續(xù)的內(nèi)存區(qū)域贷笛,其大小是在編譯時(shí)就確定的常數(shù)vs2010 可以在項(xiàng)目中右鍵--屬性窗口---鏈接器---系統(tǒng)---堆棧保留大小,這里可以更改棧的大小宙项,默認(rèn)是1M的大小 | 堆是不連續(xù)的區(qū)域乏苦,由鏈表串聯(lián)起來(lái)。這些串聯(lián)起來(lái)不連續(xù)的空間就組成了堆尤筐。堆的上限是由系統(tǒng)的有效虛擬內(nèi)存來(lái)決定的汇荐。 |
執(zhí)行效率的不同 | 由系統(tǒng)分配,速度快盆繁,但是程序員不能對(duì)其進(jìn)行操作 | 由程序員分配內(nèi)存掀淘,由于機(jī)制上的緣故,效率慢油昂,容易產(chǎn)生內(nèi)存碎片革娄,但是使用方便 |
執(zhí)行函數(shù)時(shí)的不同 | 由于棧是先入后出的特點(diǎn),所以局部變量和代碼入棧的順序和代碼表現(xiàn)的順序正好相反冕碟,比如說:函數(shù)的參數(shù)都是從右到左的入棧順序拦惋。棧有一個(gè)特點(diǎn):數(shù)據(jù)不斷入棧,它的內(nèi)存地址就會(huì)不斷減小
|
同“系統(tǒng)響應(yīng)的不同” |
總結(jié):
棧的內(nèi)存小安寺,效率高厕妖,存儲(chǔ)的數(shù)據(jù)局部有效,超出局部就消失挑庶。
堆可存儲(chǔ)空間大言秸,靈活性高,但容易產(chǎn)生碎片迎捺,效率低举畸。
三.內(nèi)存泄漏
假如我們沒有使用delete刪除一個(gè)指針指向的堆區(qū)內(nèi)存空間,然后就將這個(gè)指針重新賦值凳枝,如
[cpp]
int *p=new int();
p=new int();
上面的代碼就會(huì)造成傳說中的內(nèi)存泄漏俱恶。這是因?yàn)榈谝恍卸x一個(gè)指針p指向一塊堆區(qū)的內(nèi)存空間。第二行又將新的內(nèi)存空間地址賦給了p范舀,這樣,第一行申請(qǐng)的內(nèi)存空間由于沒有了指向它的指針了罪,也就沒辦法手動(dòng)回收了锭环,所以在使用new分配了內(nèi)存空間后一定要使用delete來(lái)釋放它。
如果不想刪除第一塊內(nèi)存空間泊藕,必須這樣做辅辩,如下:
[cpp]
int *p=new int();
int *p1=new int();