在iOS中,虛擬內(nèi)存主要分為棧區(qū)、堆區(qū)、全局(靜態(tài))區(qū)、常量區(qū)、代碼區(qū),其中全局(靜態(tài))區(qū)又分為BSS區(qū)和數(shù)據(jù)區(qū)。如下圖所示:

棧區(qū)(Stack)
棧區(qū)由編譯器自動(dòng)分配和釋放,是一塊連續(xù)的內(nèi)存區(qū)域,主要用于存放局部變量和函數(shù)的參數(shù)(id self,SEL _cmd)。
特點(diǎn)
- 棧由
編譯器自動(dòng)分配和釋放,是一塊連續(xù)的內(nèi)存區(qū)域。 - 棧內(nèi)部以
幀(Frame)的結(jié)構(gòu)進(jìn)行入棧和出棧,遵循先進(jìn)后出(FILO)原則。 - 棧是
從高地址向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),地址空間在iOS中以Ox7開頭。 - 棧
在運(yùn)行時(shí)分配。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):因?yàn)闂J怯删幾g器自動(dòng)分配和釋放,所以不會(huì)產(chǎn)生內(nèi)存碎片,且快速高效。
- 缺點(diǎn):內(nèi)存大小有限制,在iOS中,主線程中棧的大小為
1MB,子線程中棧的大小為512kb,在MAC OS中棧的大小為8MB。(詳情可見官方文檔Threading Programming Guide)
棧幀(Frame)
棧區(qū)(stack)內(nèi)存是以幀的結(jié)構(gòu)來管理的,每次執(zhí)行一個(gè)函數(shù),都會(huì)生成新的幀(Frame),所有的幀都按順序添加到棧中,最新生成的幀存放在最上面。每次新生成一幀,叫做入棧(push),每次釋放一幀,叫做出棧(pop),當(dāng)所有的幀都被釋放掉,整個(gè)棧也會(huì)被釋放。整個(gè)過程如下圖所示:

我們通過下面的實(shí)例來具體分析:
int main() {
int a = 10;
int b = 20;
return test(a, b);
}
- 當(dāng)執(zhí)行
main()函數(shù)時(shí),系統(tǒng)生成對應(yīng)的幀并入棧,main()函數(shù)里的局部變量a和b都存放在這個(gè)幀中。 - 當(dāng)執(zhí)行到
test()函數(shù)時(shí),系統(tǒng)又會(huì)生成對應(yīng)的幀并入棧,用來保存test()函數(shù)內(nèi)部的局部變量,這個(gè)新幀會(huì)疊加在最上面。 - 執(zhí)行完
test()函數(shù)后,對應(yīng)的幀被釋放,里面存放的局部變量都會(huì)被銷毀。 - 執(zhí)行完
main()函數(shù)后,對應(yīng)的幀被釋放,此時(shí)所有的幀都被釋放,整個(gè)棧區(qū)(stack)也會(huì)被釋放。
堆區(qū)(Heap)
堆區(qū)由程序員分配和釋放的,也可由垃圾回收機(jī)制釋放,是一塊不連續(xù)的內(nèi)存空間。主要存放:OC中使用alloc或者new創(chuàng)建的對象,C語言中使用malloc、calloc、realloc分配的空間(C中這些需要使用free來釋放)。
特點(diǎn)
- 堆由
程序員分配和釋放,是一塊不連續(xù)的內(nèi)存空間。 - 堆是類似于
鏈表結(jié)構(gòu)(便于增刪,不便于查詢),遵循先進(jìn)先出(FIFO)原則。 - 堆是
從低地址向高地址拓展的數(shù)據(jù)結(jié)構(gòu),地址空間在iOS中以0x6開頭。 - 堆
在運(yùn)行時(shí)分配。
優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):由于內(nèi)存空間不連續(xù),因此使用靈活方便,隨取隨用。
- 缺點(diǎn):需要手動(dòng)管理內(nèi)存,速度慢,且容易產(chǎn)生內(nèi)存碎片。
堆區(qū)對象的內(nèi)存訪問
Person *p = [Person alloc] init];
這個(gè)案例中,實(shí)例化的Person對象,存在于堆區(qū),指針變量p存放于棧區(qū),p的內(nèi)存空間存放Person對象的地址。所以,若要訪問Person對象,需要先訪問棧區(qū)的指針變量p,再通過p存放的地址來訪問Person對象。
全局(靜態(tài))區(qū)
全局區(qū)是編譯期分配的內(nèi)存空間,由系統(tǒng)管理,在程序啟動(dòng)時(shí)由分配,程序結(jié)束時(shí)釋放,內(nèi)存空間一般以0x1開頭。在程序運(yùn)行過程中,此內(nèi)存中的數(shù)據(jù)一直存在。其又分為兩部分區(qū)域:
-
BSS區(qū)(.bss):存放未初始化的全局變量和靜態(tài)變量。 -
數(shù)據(jù)區(qū)(.data):存放已初始化的全局變量和靜態(tài)變量。
全局變量是指在運(yùn)行中值可以被動(dòng)態(tài)修改的變量。
靜態(tài)變量是指由static修飾的變量,值不能被修改,包含全局靜態(tài)變量和局部靜態(tài)變量。
常量區(qū)(.rodata)
常量區(qū)是編譯時(shí)分配的內(nèi)存空間,由系統(tǒng)管理,在程序啟動(dòng)時(shí)分配,在程序結(jié)束后釋放,主要存放常量,不允許被修改,內(nèi)存空間一般以0x1開頭。
代碼區(qū)(.text)
代碼區(qū)是在編譯期分配,用來存放函數(shù)被編譯后的二進(jìn)制代碼。代碼段只允許讀操作,不允許寫操作。
