1. 程式人生 > >OC中棧和堆記憶體區別解析

OC中棧和堆記憶體區別解析

記憶體管理

移動裝置的記憶體及其有限,每一個APP所能佔用的記憶體是有限制的

什麼行為會增加APP的記憶體佔用

  • 建立一個oc物件
  • 定義一個變數
  • 呼叫一個函式或者方法

記憶體管理範圍

  • 任何繼承了NSObject的物件
  • 對其它非物件型別無效
  • 簡單來說:
    • 只有oc物件需要進行記憶體管理
    • 非oc物件型別比如基本資料型別不需要進行記憶體管理

引入堆和棧的概念

  • 所以問題就來了,為什麼OC物件需要進行記憶體管理,而其它非物件型別比如基本資料型別就不需要進行記憶體管理呢?
  • 只有OC物件才需要進行記憶體管理的本質原因?

    因為:Objective-C的物件在記憶體中是以堆的方式分配空間的,並且堆記憶體是由你釋放的,就是release


    OC物件存放於堆裡面(堆記憶體要程式設計師手動回收)
    非OC物件一般放在棧裡面(棧記憶體會被系統自動回收)

    堆裡面的記憶體是動態分配的,所以也就需要程式設計師手動的去新增記憶體、回收記憶體

堆是所有程式共享的記憶體,當N個這樣的記憶體得不到釋放,堆區會被擠爆,程式立馬癱瘓。這就是記憶體洩漏

這裡要知道的是:系統在堆區只會記錄某一個區域被使用了,並不會管你是什麼型別的(匿名訪問)。

那麼,既然是匿名訪問,堆不管你的型別了,那怎麼區分這塊記憶體是什麼型別的呢?

簡單:什麼型別指標指向這塊記憶體,這塊記憶體就是什麼型別的。

舉例說明1


該程式碼塊在記憶體中的表現形式如下圖


圖中可以看到,棧裡面存放的是非物件的基本資料型別,堆記憶體存放著oc物件


當代碼塊一過,裡面的a,b,*c指標都會被系統編譯器自動回收,因為它存放在棧裡面,而OC物件則不會被系統回收,因為它存放堆裡面,堆裡面的記憶體是動態儲存的,所以需要程式設計師手動回收記憶體

舉例說明2


變數 i 和 j 就是儲存在棧區裡的

有一句話如是說:在OC中,預設不帶*號的都是儲存在棧區的。

在這裡,變數名其實就是變數儲存在棧區的記憶體地址的別名。

那麼,這個程式執行時在棧區是如何出入的呢?

程式在棧區的出入步驟:

程式執行執行main函式,i首先進入棧區,位於最底部。然後j進入棧區,printf呼叫函式sum(i, j)緊隨其後進入棧區。

函式sum(int x, int y)中的引數,從右到左依次進入棧區。先是y再是x。

棧區儲存樣式:

當程式執行結束後,棧區內的所有元素會從上到下的依次出棧,棧會恢復到原始狀態。

棧的先進後出方式,會特別整齊的存取,不會產生記憶體碎片。

總結區別

  • 按管理方式分
    • 對於棧來講,是由系統編譯器自動管理,不需要程式設計師手動管理
    • 對於堆來講,釋放工作由程式設計師手動管理,不及時回收容易產生記憶體洩露
  • 按分配方式分
    • 堆是動態分配和回收記憶體的,沒有靜態分配的堆
    • 棧有兩種分配方式:靜態分配和動態分配
      • 靜態分配是系統編譯器完成的,比如區域性變數的分配
      • 動態分配是有alloc函式進行分配的,但是棧的動態分配和堆是不同的,它的動態分配也由系統編譯器進行釋放,不需要程式設計師手動管理
參考:http://www.jianshu.com/p/c8e1d91dda99和http://blog.csdn.net/liuhang03/article/details/49826205