1. 程式人生 > 實用技巧 >iOS記憶體的基礎探究(靜態儲存區、棧、堆)

iOS記憶體的基礎探究(靜態儲存區、棧、堆)

程式碼區存放於低地址,棧區存放於高地址。區與區之間並不是連續的。
app啟動後,程式碼區,文字常量區,全域性儲存區大小固定,指向這些區的指標不會產生崩潰性的錯誤。而堆區和棧區是時時刻刻變化的(堆的建立銷燬,棧的彈入彈出),當使用一個指標指向這兩個區的記憶體時,要注意記憶體是否已釋放,指向已經釋放的記憶體會產生野指標。

儲存區

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

亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意大小的記憶體,程式設計師自己負責在適當的時候用free或delete釋放記憶體。動態記憶體的生存期可以由我們決定,如果我們不釋放記憶體,程式將在最後才釋放掉動態記憶體(如果某動態記憶體不再使用,需要將其釋放掉,否則認為發生了記憶體洩漏現象)。

靜態儲存區(全域性儲存區)

記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個執行期間都存在。它主要存放靜態資料、全域性資料和常量。程式結束後由系統釋放。

全域性變數、靜態變數會儲存在此區域。事實上全域性變數也是靜態的,因此,也叫全域性靜態儲存區。

儲存方式:

  • 初始化的全域性變數跟靜態變數放在一片區域(資料區)
  • 未初始化的全域性變數與靜態變數放在相鄰的另一片區域(BSS區)

舉例:

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位元組的區域就在堆區。 
 }

文字常量區

在程式中使用的常量儲存在此區域(常量字串就是放在這裡的)。程式結束後,由系統釋放。在程式中使用的常量,都會到文字常量區獲取。

程式碼區

存放函式體的二進位制程式碼,執行程式就是執行程式碼,程式碼要執行就要載入進記憶體。在程式結束後由系統釋放。

棧與堆的比較:

1. 申請後的系統是如何響應

  • 棧:儲存每一個函式在執行的時候都會向作業系統索要資源,棧區就是函式執行時的記憶體,棧區中的變數由編譯器負責分配和釋放,記憶體隨著函式的執行分配,隨著函式的結束而釋放,由系統自動完成。注意:只要棧的剩餘空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示棧溢位。
  • 堆:首先應該知道作業系統有一個記錄空閒記憶體地址的連結串列。當系統收到程式的申請時,會遍歷該連結串列,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配給程式。由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒連結串列中。

2. 申請大小的限制

  • 棧:棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域。是棧頂的地址和棧的最大容量是系統預先規定好的,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數 ) ,如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。
  • 堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。

3. 申請效率的比較

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

轉自: