1. 程式人生 > >Objective-C 記憶體管理機制

Objective-C 記憶體管理機制

一、Objective-C記憶體管理的物件

1、IOS開發中,記憶體中的物件主要有兩類

一類是值型別,比如int、float、struct等基本資料型別。
一類是引用型別,也就是繼承自NSObject類的所有的OC物件。前一種值型別不需要我們管理,後一種引用型別是需要我們管理記憶體的,一旦管理不好,就會產生非常糟糕的後果。

2、為什麼值型別不需要管理,而引用型別需要管理呢?

1)那是因為他們分配記憶體方式不一樣。
  A、值型別會被放入棧中,他們依次緊密排列,在記憶體中佔有一塊連續的記憶體空間,遵循先進後出的原則。
  B、引用型別會被放到堆中,當給物件分配記憶體空間時,會隨機的從記憶體當中開闢空間,物件與物件之間可能會留有不確定大小的空白空間,因此會產生很多記憶體碎片,需要我們管理。

2)棧記憶體與堆記憶體從效能上比較:棧記憶體要優於堆記憶體,這是因為棧遵循先進後出的原則,但是當資料量過大時,存入棧會明顯的降低效能。因此,我們會把大量的資料存入堆中,然後棧中存放堆的地址,當需要呼叫資料時,就可以快速的通過棧內的地址找到堆中的資料。

3)值型別和引用型別之間是可以相互轉化的:
  A、把值型別轉化為引用型別的過程叫做裝箱,比如把int包裝為NSNumber,這個過程會增加程式的執行時間,降低效能。
  B、把引用型別轉為值型別的過程叫做拆箱,比如把NSNumer轉為float,在拆箱的過程中,我們一定要注意資料原有的型別,如果型別錯誤,可能導致拆箱失敗,因此會存在安全性的問題。
  C、手動的拆箱和裝箱,都會增加程式的執行時間,降低程式碼可讀性,影響效能。

二、為什麼要使用記憶體管理

  因為Objc中所有的物件都是動態記憶體分配的,也就是都建立在堆控制元件中,整個過程由程式設計師來控制。其實objc物件的所有權,誰申請誰釋放等都強調的是⼀件事,那就是責任制。整個物件的生命週期我們都要負責,所以我們需要⼀個穩定而合理的記憶體管理,出現了記憶體洩露的問題,因為程式設計師懶或疏忽了或是由程式結構造成的。

三、Objective-C管理記憶體的方式

1、引用計數

  這是一種古老但有效的記憶體管理方式。每個物件(特指:類的例項)內部都有一個retainCount的引用計數,物件剛被建立時,引用計數為1;可以手動呼叫retain方法使引用計數加1;同樣也可以手動呼叫release方法使引用計數減1。呼叫release方法時,如果retainCount值減到0,系統將自動呼叫物件的dealloc方法(類似於c#中的dispose方法),開發人員可以在dealloc中釋放或清理資源。

2、OC中提供了兩種記憶體管理機制MRC和ARC來滿足不同的需求。

1)MRC與ARC區別如下圖所示。

這裡寫圖片描述

2)MRC手動管理記憶體(人工引用計數Mannul Reference Counting)

  MRC模式下,所有的物件都需要手動的新增retain、release程式碼來管理記憶體。使用MRC,需要遵守誰建立,誰回收的原則。也就是誰alloc,誰release;誰retain,誰release。
  當引用計數為0的時候,必須回收,引用計數不為0,不能回收,如果引用計數為0,但是沒有回收,會造成記憶體洩露。如果引用計數為0,繼續釋放,會造成野指標。為了避免出現野指標,我們在釋放的時候,會先讓指標=nil。

3)ARC自動管理記憶體(自動引用計數Automatic Reference Counting)。

  ARC是IOS5推出的新功能,通過ARC,可以自動的管理記憶體。在ARC模式下,只要沒有強指標(強引用)指向物件,物件就會被釋放。在ARC模式下,不允許使用retain、release、retainCount等方法。並且,如果使用dealloc方法時,不允許呼叫[super dealloc]方法。
  ARC模式下的property變數修飾詞為strong、weak,相當於MRC模式下的retain、assign。strong :代替retain,預設關鍵詞,代表強引用。weak:代替assign,聲明瞭一個可以自動設定nil的弱引用,但是比assign多一個功能,指標指向的地址被釋放之後,指標本身也會自動被釋放。

四、與記憶體有關的修飾符

1、讀寫性修飾符:readwrite | readonly

  readwrite:表明這個屬性是可讀可寫的,系統為我們建立這個屬性的setter和getter方法。
  
  readonly:表明這個屬性只能讀不能寫,系統只為我們建立一個getter方法,不會建立setter方法

  系統預設是readwrite

2、strong | weak | assign | retain | copy

  strong就表示是強引⽤型別,就相當於MRC中的retain。針對物件型別進行記憶體管理。如果對基本資料型別使用,則Xcode會直接報錯。當給物件型別使用此修飾符時,setter方法會先將舊的物件屬性release掉,再對新的物件進行一次賦值並進行一次retain操作。

  weak就表示的時弱引⽤型別,就相當於MRC中的assign。但是它比assign安全;assign是直接賦值,可能會出現野指標的情況。但是weak不會出現野指標,weak會自動置成 nil。

  assign:表示直接賦值,用於基本資料型別(NSInteger和CGFloat)和C資料型別(如int, float, double, char等)另外還有id型別,這個修飾符不會牽涉到記憶體管理。但是如果是物件型別,使用此修飾符則可能會導致記憶體洩漏或EXC_BAD_ACCESS錯誤

  copy:主要用在NSString型別,表示複製內容。
  
  對於普通的OC物件系統預設屬性是strong,對於基本資料型別系統預設屬性是assign。
  

3、原子性修飾符:atomic | nonatomic

  atomic:表示是執行緒安全的。
  
  nonatomic:表示是非執行緒安全的,使用此屬性效能會提高一些。

  系統預設是atomic

4、getter和setter修飾符

  @property(getter = getMethodName, setter = setMethodName) Object *obj;
  這兩個屬性修飾符用於設定自定義生成的getter和setter方法名,使用之後將不再使用系統預設的setter和getter方法名。

五、MRC與ARC混編

  MRC與ARC理論上是不能相容的,也就是你如果建立的專案是ARC模式的,在你的程式碼中是不能使用release,否則會出現記憶體問題。現在大部分程式都會選擇ARC的方式,但是很多第三方的框架是MRC模式,如果想把這些第三方的檔案加到自己專案中,需要進行標識,否則編譯的時候會出現錯誤。

  在ARC的專案中,對MRC的檔案可以新增編譯選項-fno-objc-arc的標識;在MRC的專案中,對ARC的檔案可以新增編譯選項 -fobjc-arc的標識。 步驟如下圖所示。
這裡寫圖片描述

  把MRC檔案轉為ARC,實際上是去掉檔案中的retain、release,因此也通過下圖中方式完成。
這裡寫圖片描述