天天看點

初入OC-記憶體管理

一、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,是以也通過下圖中方式完成。 

轉載于:https://my.oschina.net/jdking/blog/2248132