內(nèi)存分區(qū)
-
棧(stack)
由編譯器自動(dòng)分配釋放,無需手工管理挠蛉;
存放函數(shù)的參數(shù)值、局部變量等肄满;
操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧谴古,后入先出;
棧區(qū)地址從高到低分配稠歉,是一塊連續(xù)的內(nèi)存區(qū)域掰担,棧頂?shù)刂泛腿萘渴窍到y(tǒng)預(yù)先規(guī)定好的,因此能獲得的棧的空間較小怒炸。 -
堆(heap)
用于動(dòng)態(tài)內(nèi)存分配带饱;
由程序員分配釋放,若程序員不釋放阅羹,則可能造成內(nèi)存泄露纠炮,程序 結(jié)束時(shí)有可能由OS回收;
堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)灯蝴,是不連續(xù)的內(nèi)存區(qū)域,這是由于系統(tǒng)是用鏈表來存儲(chǔ)空閑內(nèi)存地址的孝宗,自然是不連續(xù)的穷躁,而鏈表的遍歷方向是由低到高地址的。堆的大小受制于計(jì)算機(jī)中的有效虛擬內(nèi)存因妇,所以堆獲得的空間比較大且靈活问潭。 -
全局區(qū)/靜態(tài)區(qū)(Data Segment)
全局變量和靜態(tài)變量在內(nèi)存中是放在一起的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域婚被,未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域狡忙;
該塊內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好了,在整個(gè)程序運(yùn)行期間始終不變址芯,程序結(jié)束后由系統(tǒng)釋放灾茁。 -
常量區(qū)
存放常量,不允許修改谷炸,常量字符串存放在這里北专,程序結(jié)束后由系統(tǒng)釋放。
-
代碼區(qū)(text segment)
存放函數(shù)體的二進(jìn)制代碼
整個(gè)內(nèi)存區(qū)域由高地址到低地址如下圖所示:
堆和棧的區(qū)別
管理方式不同
棧是由編譯器自動(dòng)管理旬陡,無需程序員手工控制拓颓;堆空間的申請和釋放是由程序員控制的,容易產(chǎn)生內(nèi)存泄露描孟。-
空間大小不同
棧是由高向低擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)驶睦,是一塊連續(xù)的區(qū)域砰左。棧頂?shù)牡刂泛蜅5淖畲笕萘渴怯上到y(tǒng)預(yù)先設(shè)定好的,當(dāng)申請的空間超過棧的剩余空間的時(shí)候场航,就提示溢出缠导,所以棧的空間較小。堆是由低向高擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)旗闽,是不連續(xù)的內(nèi)存區(qū)域酬核。堆的大小受制于計(jì)算機(jī)中的有效虛擬內(nèi)存,所以堆獲得的空間比較大且靈活适室。
是否產(chǎn)生碎片
對于堆來講嫡意,頻繁的創(chuàng)建銷毀勢必會(huì)造成內(nèi)存空間的不連續(xù),從而產(chǎn)生大量的碎片捣辆,使程序效率降低蔬螟。而棧則沒有這個(gè)問題,因?yàn)闂J窍冗M(jìn)后出的隊(duì)列汽畴,他們是如此的一一對應(yīng)旧巾,以至于永遠(yuǎn)都不可能有一個(gè)內(nèi)存塊從棧中彈出。增長方向不同
棧的增長方向是向下的忍些,是向著內(nèi)存地址減小的方向鲁猩;而堆則相反。分配方式不同
堆都是動(dòng)態(tài)分配的罢坝,沒有靜態(tài)分配的堆廓握。棧有兩種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是編譯器完成的嘁酿,比如局部變量的分配隙券。動(dòng)態(tài)分配是有alloc函數(shù)進(jìn)行分配的,但是棧的動(dòng)態(tài)分配和堆是不同的闹司,他的動(dòng)態(tài)分配由編譯器進(jìn)行釋放娱仔,無需我們手工實(shí)現(xiàn)。 棧的分配釋放是由編譯器完成的游桩,棧也有動(dòng)態(tài)分配牲迫,但其和堆是不同的,無需手工實(shí)現(xiàn)借卧;而堆是動(dòng)態(tài)分配的恩溅。分配效率不同
棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會(huì)在底層對棧提供支持:分配專門的寄存器存放棧的地址谓娃,壓棧出棧都有專門的指令執(zhí)行脚乡。
而堆的機(jī)制復(fù)雜的多,例如為了分配一塊內(nèi)存,庫函數(shù)會(huì)按照一定的算法(具體的算法可以參考數(shù)據(jù)結(jié)構(gòu)/操作系統(tǒng))在堆內(nèi)存中搜索可用的足夠大的空間奶稠,如果沒有足夠大的空間(可能是由于內(nèi)存碎片太多)俯艰,就有需要操作系統(tǒng)來重新整理內(nèi)存空間,這樣就有機(jī)會(huì)分到足夠大小的內(nèi)存锌订,然后返回竹握。顯然,堆的效率比棧要低得多辆飘。
其他
之所以分成這么多個(gè)區(qū)域啦辐,主要基于以下考慮:
一個(gè)進(jìn)程在運(yùn)行過程中,代碼是根據(jù)流程依次執(zhí)行的蜈项,只需要訪問一次芹关,當(dāng)然跳轉(zhuǎn)和遞歸有可能使代碼執(zhí)行多次,而數(shù)據(jù)一般都需要訪問多次紧卒,因此單獨(dú)開辟空間以方便訪問和節(jié)約空間侥衬。
臨時(shí)數(shù)據(jù)及需要再次使用的代碼在運(yùn)行時(shí)放入棧區(qū)中,生命周期短跑芳。
全局?jǐn)?shù)據(jù)和靜態(tài)數(shù)據(jù)有可能在整個(gè)程序執(zhí)行過程中都需要訪問轴总,因此單獨(dú)存儲(chǔ)管理。
堆區(qū)由用戶自由分配博个,以便管理怀樟。
//main.cpp
int a = 0; 全局初始化區(qū)
char *p1; 全局未初始化區(qū)
main()
{
int b; 棧
char s[] = "abc"; 棧
char *p2; 棧
char *p3 = "123456"; 123456\0在常量區(qū),p3在棧上盆佣。
static int c =0往堡; 全局(靜態(tài))初始化區(qū)
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。
strcpy(p1, "123456"); 123456\0放在常量區(qū)罪塔,編譯器可能會(huì)將它與p3所指向的"123456"優(yōu)化成一個(gè)地方。
}
棧是一個(gè)用來存儲(chǔ)局部和臨時(shí)變量的存儲(chǔ)空間养葵。在現(xiàn)代操作系統(tǒng)中,一個(gè)線程會(huì)分配一個(gè)棧. 當(dāng)一個(gè)函數(shù)被調(diào)用,一個(gè)stack frame(棧幀)就會(huì)被壓到stack里征堪。里面包含這個(gè)函數(shù)涉及的參數(shù),局部變量,返回地址等相關(guān)信息。當(dāng)函數(shù)返回后,這個(gè)棧幀就會(huì)被銷毀关拒。而這一切都是自動(dòng)的,由系統(tǒng)幫我們進(jìn)行分配與銷毀佃蚜。對于程序員來說,我們無須自己調(diào)度着绊。
在objective-c中只支持一個(gè)類型對象:blocks谐算。
關(guān)于在block中的對象的生命周期問題。出現(xiàn)這問題的原因是归露,block是新的對象洲脂,當(dāng)你使用block時(shí)候,如果你想對其保持引用剧包,你需要對其進(jìn)行copy操作恐锦,(從棧上copy到堆中往果,并返回一個(gè)指向他的指針),而不是對其進(jìn)行retain操作