1. 程式人生 > >iOS程式中的記憶體分配 棧區 堆區 全域性區(靜態區) 常量區 方法區

iOS程式中的記憶體分配 棧區 堆區 全域性區(靜態區) 常量區 方法區

在計算機系統中,執行的應用程式的資料都是儲存在記憶體中的,不同型別的資料,儲存的記憶體區域不同。
一、記憶體分割槽

  1. 棧區(stack) 由編譯器自動分配並釋放,存放函式的引數值,區域性變數等。棧是系統資料結構,對應執行緒/程序是唯一的。
    優點是快速高效,缺點時有限制,資料不靈活。[先進後出]

    棧空間分靜態分配 和動態分配兩種。

     靜態分配是編譯器完成的,比如自動變數(auto)的分配。
     動態分配由alloca函式完成。
     棧的動態分配無需釋放(是自動的),也就沒有釋放函式。
     為可移植的程式起見,棧的動態分配操作是不被鼓勵的!
  2. 堆區(heap) 由程式設計師分配和釋放,如果程式設計師不釋放,程式結束時,可能會由作業系統回收 ,比如在ios 中 alloc 都是存放在堆中。
    優點是靈活方便,資料適應面廣泛,但是效率有一定降低。[順序隨意]

     堆是函式庫內部資料結構,不一定唯一。
     不同堆分配的記憶體無法互相操作。
     堆空間的分配總是動態的

    雖然程式結束時所有的資料空間都會被釋放回系統,但是精確的申請記憶體,釋放記憶體匹配是良好程式的基本要素。

  3. 全域性區(靜態區) (static) 全域性變數和靜態變數的儲存是放在一起的,初始化的全域性變數和靜態變數存放在一塊區域,未初始化的全域性變數和靜態變數在相鄰的另一塊區域,程式結束後有系統釋放。

    注意:全域性區又可分為未初始化全域性區:
         .bss段和初始化全域性區:data段。
         舉例:int a;未初始化的。int a = 10;已初始化的。

    例子程式碼:

      int a = 10;  全域性初始化區
      char *p;  全域性未初始化區
    
     main{
       int b; 棧區
       char s[] = "abc" 棧
       char *p1; 棧 
       char *p2 = "123456";  123456\\\\0在常量區,p2在棧上。
       static int c =0; 全域性(靜態)初始化區 
    
       w1 = (char *)malloc(10); 
       w2 = (char *)malloc(20); 
       分配得來得10和20位元組的區域就在堆區。 
     }
  4. 文字常量區 存放常量字串,程式結束後由系統釋放
  5. 程式程式碼區 存放函式的二進位制程式碼

二、申請後的系統響應

  1. 棧:儲存每一個函式在執行的時候都會向作業系統索要資源,棧區就是函式執行時的記憶體,棧區中的變數由編譯器負責分配和釋放,記憶體隨著函式的執行分配,隨著函式的結束而釋放,由系統自動完成。

    注意:只要棧的剩餘空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示棧溢位。

  2. 堆:
    1.首先應該知道作業系統有一個記錄空閒記憶體地址的連結串列。
    2.當系統收到程式的申請時,會遍歷該連結串列,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配給程式。
    3 .由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒連結串列中 

三、 申請大小的限制

  1. 棧:棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域。是棧頂的地址和棧的最大容量是系統預先規定好的,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數 ) ,如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。

  2. 堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。


    記憶體分配.png

棧:由系統自動分配,速度較快,不會產生記憶體碎片
堆:是由alloc分配的記憶體,速度比較慢,而且容易產生記憶體碎片,不過用起來最方便

打個比喻來說: 

使用棧就象我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。 

使用堆就象是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。

文/Liwjing(簡書作者)
原文連結:http://www.jianshu.com/p/f3c1b920e8eb

總結iOS中的堆和棧的區別

管理方式:

對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來講,釋放工作有程式設計師控制,容易產生memory Leak。

申請大小:

棧:在Windows下,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體區域。這句話的意思是棧頂上的地址和棧的最大容量是系統預先規定好的,在Windows下,棧的大小是2M(也有的說1M,總之是編譯器確定的一個常數),如果申請的空間超過了棧的剩餘空間時候,就overflow。因此,能獲得棧的空間較小。

堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大笑受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。

碎片的問題:

對於堆來講,頻繁的new/delete勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題,因為棧是先進後出的佇列,他們是如此的一一對應,以至於永遠都不可能有一個記憶體快從棧中彈出。

分配方式:

堆都是動態分配的,沒有靜態分配的堆。棧有兩種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配是有alloc函式進行分配的,但是棧的動態分配和堆是不同的,他的動態分配由編譯器進行釋放,無需我們手工實現。

分配效率:

棧是機器系統提供的資料結構,計算機會在底層堆疊提供支援,分配專門的暫存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函式庫提供的,他的機制是很複雜的。