相信很多iOS開發(fā)者對內(nèi)存分配的概念比較模糊,沒有去好好研究與我們經(jīng)常打交道的變量,是如何分配內(nèi)存的。很多小伙伴應(yīng)該對棧區(qū)和堆區(qū)的概念還應(yīng)該是大學(xué)里時候的記憶吧,估計很多可能也忘得差不多了(算我一個??),所以今天整理了一下,順便做個筆記,歡迎圍觀_。如有其它見解,可以提出來相互學(xué)習(xí)交流。

在計算機系統(tǒng)中,運行的應(yīng)用程序的數(shù)據(jù)都是保存在內(nèi)存中的,不同類型的數(shù)據(jù),保存的內(nèi)存區(qū)域也不同。
1.內(nèi)存分區(qū)
棧區(qū)(stack):
- 由編譯器自動分配并釋放,存放函數(shù)的參數(shù)值,局部變量等;
- 不需要程序員管理棧區(qū)變量的內(nèi)存;
- 有靜態(tài)分配和動態(tài)分配(1. 靜態(tài)分配是系統(tǒng)編譯器完成的,比如局部變量的分配; 2. 動態(tài)分配是有alloc函數(shù)進行分配的,但是棧的動態(tài)分配和堆是不同的,它的動態(tài)分配也由系統(tǒng)編譯器進行釋放,不需要程序員手動管理);
- 地址從高到低分配;
- 優(yōu)點是快速高效,缺點時有限制,數(shù)據(jù)不靈活;
堆區(qū)(heap):
- 由程序員分配和釋放,如果程序員不釋放,程序結(jié)束時,可能會由操作系統(tǒng)回收 ;
- 堆區(qū)的內(nèi)存分配使用的是alloc;
- 需要程序員管理內(nèi)存,不及時回收容易產(chǎn)生內(nèi)存泄露(ARC的內(nèi)存的管理,是編譯器再便宜的時候自動添加 retain、release、autorelease);
- 都是動態(tài)分配和回收內(nèi)存的;
- 堆區(qū)的地址是從低到高分配
- 優(yōu)點是靈活方便,數(shù)據(jù)適應(yīng)面廣泛,但是效率有一定降低;
全局區(qū)/靜態(tài)區(qū)(static):
- 包括兩個部分:未初始化過 、初始化過;
- 初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域;
eg:int a;未初始化的。int a = 10;已初始化的。常量區(qū):
- 存放常量字符串,程序結(jié)束后由系統(tǒng)釋放;
代碼區(qū):
- 存放函數(shù)的二進制代碼;
如下圖所示:代碼區(qū)存放于低地址,棧區(qū)存放于高地址。區(qū)與區(qū)之間并不是連續(xù)的。

2.內(nèi)存申請
棧:
存儲每一個函數(shù)在執(zhí)行的時候都會向操作系統(tǒng)索要資源,棧區(qū)就是函數(shù)運行時的內(nèi)存,棧區(qū)中的變量由編譯器負責分配和釋放,內(nèi)存隨著函數(shù)的運行分配,隨著函數(shù)的結(jié)束而釋放,由系統(tǒng)自動完成。
注意:只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢出(overflow)。
堆:
1.首先應(yīng)該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表。
2.當系統(tǒng)收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結(jié)點,然后將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點的空間分配給程序。
3 .由于找到的堆結(jié)點的大小不一定正好等于申請的大小,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中
3.申請大小的限制
棧:棧是向低地址擴展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數(shù) ) ,如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。
棧:由系統(tǒng)自動分配,速度較快,不會產(chǎn)生內(nèi)存碎片
堆:是由alloc分配的內(nèi)存,速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便
4.舉個栗子??
int a = 10; //全局初始化區(qū)
char *p; //全局未初始化區(qū)
main
{
int b; //棧區(qū)
char s[] = "abc" //棧
char *p1; //棧
char *p2 = "123456";//123456值在常量區(qū),p2指針在棧上。
static int c = 0; //全局(靜態(tài))初始化區(qū)
w1 = (char *)malloc(10);
w2 = (char *)malloc(20);
//分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。
}