iOS程序中的內(nèi)存分配(棧區(qū)和堆區(qū)的對比)

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

coverImage.jpg

在計算機系統(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ù)的。


內(nèi)存分區(qū)示意圖.png

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ū)。
}

今天的整理就到這,祝大家玩得愉快!(*  ̄3)(ε ̄ *)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容