stack 棧
stack是存在于某作用域(scope)的一塊內(nèi)存空間(memory space)。例如當(dāng)調(diào)用函數(shù)時(shí)台猴,函數(shù)本身就會(huì)形成一個(gè)stack用來(lái)放置他所接受的參數(shù)朽合,以及返回地址。在函數(shù)體(function body)內(nèi)聲明的任何變量饱狂,其所使用的內(nèi)存塊都取自上述的stack旁舰。
heap 堆
heap又稱(chēng)System heap,是指由操作系統(tǒng)提供的一塊global內(nèi)存空間嗡官。程序可動(dòng)態(tài)分配(dynamic allocated)從中獲得若干區(qū)塊(block)
{
Complex c1(1,2); //c1所占的空間在棧stack上
Complex *p = new Complex(1,2);// Complex(1,2)是一個(gè)臨時(shí)變量箭窜,它所占的內(nèi)存空間是使用new關(guān)鍵字從heap堆中動(dòng)態(tài)分配得來(lái)的,
// 并且這塊內(nèi)存由指針p指向
}
棧和堆上各種對(duì)象的生命周期
stack object 棧對(duì)象的聲明周期
上面例子中的C1就是stack object(存放在棧上的對(duì)象),其生命在作用與結(jié)束之際結(jié)束衍腥,這種作用域內(nèi)的對(duì)象又稱(chēng)auto object或local object磺樱,因?yàn)樗麜?huì)被“自動(dòng)清理”。
static object 靜態(tài)對(duì)象的生命周期
static object(靜態(tài)對(duì)象)其生命在作用域結(jié)束之后仍然存在婆咸,直到整個(gè)程序結(jié)束竹捉,其才會(huì)被“清理”。出了作用域的靜態(tài)對(duì)象尚骄,雖然存在但不可見(jiàn)块差。這種變量常可以用來(lái)作為計(jì)數(shù)器倔丈,用來(lái)記錄程序經(jīng)過(guò)作用域的次數(shù)憨闰。如下:
int count_function(){
static cnt = 0;//static object在被定義的時(shí)候初始化,且只初始化這一次需五,再次進(jìn)入函數(shù)會(huì)略過(guò)此句鹉动。
cnt++;
return cnt;
}
global object 全局對(duì)象的生命周期
寫(xiě)在任何作用域之外(或稱(chēng)為在全局域中)的對(duì)象叫做global object(全局對(duì)象)。其生命在程序開(kāi)始時(shí)開(kāi)始宏邮,程序結(jié)束時(shí)結(jié)束泽示,可以把他看作是全局域中的靜態(tài)對(duì)象缸血。
heap object 堆對(duì)象的生命周期
{
Complex *p = new Complex(1,2);
……
delete p;
}
指針p所指向的對(duì)象就是heap object(堆對(duì)象),其生命始于new械筛,止于delete捎泻。在其作用域內(nèi)只new不delete,會(huì)發(fā)生內(nèi)存泄漏埋哟。如下:
{
Complex *p = new Complex;
}
因?yàn)闂?duì)象指針p離開(kāi)作用域后就自動(dòng)釋放了笆豁。也就是指向堆內(nèi)被分配的這塊內(nèi)存的指針失效了,但是這塊堆上的內(nèi)存仍然被標(biāo)記為“已使用”定欧。而這塊內(nèi)存沒(méi)辦法通過(guò)delete p去釋放內(nèi)存渔呵,將永遠(yuǎn)被占用,直至程序結(jié)束砍鸠。如果這個(gè)作用域被程序多次經(jīng)過(guò)扩氢,每次都會(huì)分配內(nèi)存不釋放,就會(huì)耗光內(nèi)存爷辱,導(dǎo)致系統(tǒng)變慢录豺,甚至程序崩潰。
new和delete
new和delete分別是在系統(tǒng)堆中分配和釋放內(nèi)存的指令饭弓,必須成對(duì)使用双饥。除此之外還有new[] (array new)和delete[](array delete)分別是在系統(tǒng)堆中分配數(shù)組和釋放數(shù)組的,也要成對(duì)使用弟断。
new的編譯器原理
new一個(gè)不帶指針的heap object
new一個(gè)帶指針的heap object
delete的編譯器原理
delete一個(gè)不帶指針的heap object
delete一個(gè)帶指針的heap object
在VC編譯器上動(dòng)態(tài)分配內(nèi)存的原理
cookie和補(bǔ)位內(nèi)存塊
在VC編譯器中咏花,所有動(dòng)態(tài)分配的內(nèi)存塊的大小都是16byte的整數(shù)倍。并且都是以4byte的cookie頭和4byte的cookie尾作為動(dòng)態(tài)內(nèi)存的起始標(biāo)志阀趴。其中cookie頭尾的內(nèi)容一致庸推,保存了當(dāng)前動(dòng)態(tài)分配的內(nèi)存塊的大小和使用與釋放與否的標(biāo)記信息转砖。
其中要求所有內(nèi)存塊都是16byte的整數(shù)倍是因?yàn)檗D(zhuǎn)換成十六進(jìn)制后最后一位都為0,如64byte:0x40搭盾,16byte = 0x10罪塔。剩下最后一位為0是為了標(biāo)記此塊內(nèi)存是正在使用(末位置1)還是已經(jīng)被釋放(末位置0)掌敬。
為了讓分配的內(nèi)存塊大小是16byte的整數(shù)倍孙援,可能會(huì)有多余的內(nèi)存需要填補(bǔ)乘碑,VC編譯器的做法是不足16整數(shù)倍字節(jié)的部分用00000000的內(nèi)存塊補(bǔ)足(4byte一條)。
debug模式
debug模式會(huì)額外再對(duì)象實(shí)際占用的內(nèi)存頭和尾分別加入32byte和4byte的debug信息塊据块,而release模式則沒(méi)有此信息码邻。
動(dòng)態(tài)分配內(nèi)存塊計(jì)算方式
debug模式下的動(dòng)態(tài)內(nèi)存分配的
內(nèi)存塊大小=cookie頭尾(4byte*2)+ debug頭尾(32byte+4byte)+數(shù)據(jù)實(shí)際占用空間 (n byte)+ 補(bǔ)位(pad byte)
release模式下的動(dòng)態(tài)內(nèi)存分配
release模式下只比debug少了debug信息的頭尾塊:
內(nèi)存塊大小=cookie頭尾(4byte*2)+數(shù)據(jù)實(shí)際占用空間 (n byte)+ 補(bǔ)位(pad byte)
類(lèi)對(duì)象數(shù)組的內(nèi)存占用情況
動(dòng)態(tài)分配類(lèi)對(duì)象數(shù)組的內(nèi)存占用除了上面介紹的cookie頭尾,debug頭尾瑰钮,補(bǔ)位內(nèi)存還會(huì)在實(shí)際占用內(nèi)存中多分配4byte用來(lái)存放數(shù)組的大忻疤病(size)
內(nèi)存塊大小=cookie頭尾(4byte2)+ debug信息頭尾 + size(4byte)+數(shù)據(jù)實(shí)際占用空間(n byte) 數(shù)組size +補(bǔ)位(pad byte)
下面分別用圖來(lái)表示各種情況下內(nèi)存占用情況:
動(dòng)態(tài)分配不帶pointer的單個(gè)class對(duì)象(debug模式和release模式)
debug模式
release模式
動(dòng)態(tài)分配帶pointer的單個(gè)class對(duì)象(debug模式和release模式)
動(dòng)態(tài)分配不帶pointer的class對(duì)象數(shù)組(debug模式和release模式)
動(dòng)態(tài)分配帶pointer的class對(duì)象數(shù)組(debug模式和release模式)
不成對(duì)使用new[]和delete[]的潛在危機(jī)
new[] 和delete[]必須成對(duì)使用,如果使用了new[]卻使用delete釋放浪谴,對(duì)于不帶指針的類(lèi)开睡,不會(huì)有任何影響,因?yàn)閿?shù)組元素對(duì)象苟耻,會(huì)自動(dòng)在作用域結(jié)束時(shí)釋放篇恒;但是,對(duì)于帶指針的類(lèi)凶杖,就會(huì)導(dǎo)致只調(diào)用一次析構(gòu)函數(shù)胁艰,即只有數(shù)組的第一個(gè)元素里分配的動(dòng)態(tài)內(nèi)存得到了釋放,其他元素的動(dòng)態(tài)內(nèi)存則發(fā)生內(nèi)存泄漏智蝠。而由cookie引領(lǐng)的那塊內(nèi)存會(huì)正常通過(guò)delete釋放腾么。也就是說(shuō),對(duì)于帶指針的類(lèi)對(duì)象數(shù)組杈湾,帶cookie的動(dòng)態(tài)內(nèi)存部分不會(huì)泄漏解虱,泄漏的是類(lèi)內(nèi)部通過(guò)指針指向的內(nèi)存部分。