Objective-C內存管理之-引用計數

本文會繼續深刻學習OC內存管理,內容主要參考iOS高級編程,Objective-C基礎教程,瘋狂iOS講義,是我學習內存管理的筆記objective-c

內存管理

1 內存管理的基本概念

1.1 Objective-C中的內存管理

  • 手動內存管理和自動釋放池---MRC>(Mannul Reference Counting)
  • 自動內存管理---ARC>(Automatic Reference Count)
  • 自動垃圾回收---GC>(Garbage Collection)
因爲iOS系統不支持垃圾回收,因此咱們在iOS開發中只能使用MRC和ARC來進行內存管理,本文再也不介紹Objective-C中的垃圾回收機制,可是此處注意Objective-C中是存在垃圾回收機制的

1.2 內存管理中存在的問題

  • 內存泄露:再也不須要的對象沒有釋放編程

    引發的問題:程序的內存佔有量不斷增長,最終會被耗盡致使程序崩潰
  • 野指針:沒有進行初始化得指針函數

    引發的問題:浪費內存資源,若是調用程序會出現未知的結果,甚至致使程序崩潰學習

  • 懸空指針:一個指針指向一個被銷燬的對象指針

    引發的問題:調用懸空指針指向的屬性或者方法時,程序會出現未知的結果,甚至致使程序崩潰調試

  • 殭屍對象:過分釋放的對象code

    引發的問題:對象

2.手動內存管理和自動釋放池---MRC>(Mannul Reference Counting)

2.1 什麼是引用計數(Reference Counting)

引用計數:Objective-C中引入了引用計數這一機制來跟蹤並處理對象的生命週期,繼承

管理方式:每一個對象都有一個與之關聯的整數,這個整數被稱爲引用計數,在Objective-C中,經過不一樣的方法能夠對引用計數進行操做,具體的處理以下表:教程

對象操做 Objective-C方法 對應的操做結果
生成並持有對象 alloc, new, copy,mutableCopy等方法 生成對象並設置引用計數 =1
持有對象 reatain方法 使引用計數 +1
釋放對象 release方法 使引用計數 -1
廢棄對象 dealloc方法---系統自動調用 引用計數 =0 時調用

關於delloc方法:dealloc方法繼承自NSObject,所以全部的對象都具備此方法,當一個對象的引用計數爲0時,也就意味着沒有任何程序須要此對象,系統會回收該對象所佔用的內存,在系統銷燬對象以前,會自動調用該對象的dealloc方法來執行一些回收操做,若是該對象還持有其餘對象的引用,咱們必須重寫dealloc方法來釋放該對象引用的其餘對象(一般就是使用該對象的release方法)

引用計數機制回收對象的說明:若是一個對象的引用計數爲0,則代表程序已經再也不須要它,這時系統會自動回收該對象所佔內存,相反,若是一個對象的引用計數不爲0,系統就不該該回收,也不會回收它所佔的內存

關於retainCount方法:Objective-C提供了retainCount方法來返回一個對象當前的引用計數

如何重寫dealloc方法:

- (void)dealloc {

    // 處理該對象的其餘引用(經過release方法)
    
    /** 回調父類的dealloc方法 */
    [super dealloc];
}

2.2 蘋果如何管理引用計數

  • 2.2.1 由於NSObject類的源代碼沒有公開,咱們利用Xcode的調試器(lldb)和iOS大概追溯出其實現過程
    • alloc

      +alloc
      +allocWithZone: 
      class_createInstance        //此方法能夠經過objc4中的runtime/objc-runtime-new.mm確認
      calloc                      // 分配內存塊
    • retainCount

      -retainCount 
      __CFDoExternRefOperation    // 此函數根據retain,retainCount,release操做進行分發,調用__CFBasicHashXXX方法
      CFBasicHashGetCountOfKey
    • retain

      -retain
      __CFDoExternRefOperation 
      CFBasicHashAddValue
    • release

      -release 
      __CFDoExternRefOperation 
      CFBasicHashRemoveValue      // 當此函數返回0時, -release調用dealloc方法
  • 2.2.2 由__CFDoExternRefOperation函數以及此函數的調用關係,咱們大概推算蘋果大概是使用散列表(引用計數表)來管理引用計數
    • 經過引用計數表來管理引用計數的好處:
      • 對象用內存塊的分配無須考慮內存塊頭部
      • 引用計數表各記錄中存有內存塊的地址,可從各個記錄追溯到各對象的內存塊(在進行內存泄露的檢查時,此條特性具備舉足輕重的做用,即便出現故障致使對象佔用的內存塊損壞,可是隻要引用計數表沒有被破壞,咱們就能夠肯定各內存塊的位置,這就是設置全局斷點能夠查出哪裏出現內存泄露的緣由)
        引用計數表

2.3 內存管理的思考方式

  1. 本身生成的對象,本身持有

    1.1 使用alloc new copy mutableCopy建立的對象只能本身持有

    id obj1 = [[NSObject alloc] init];
    id obj2 = [NSObject new];
    id obj3 = [NSObject copy];
    id obj4 = [NSObject mutableCopy];

    1.2 使用以上名稱的開頭的方法也意味着本身生成並持有對象

    allocNewObject

    newNewObject

    copyNewObject

    mutableCopyNewObject

  2. 非本身生成的對象,本身也能持有

    2.1 非alloc new copy mutableCopy生成的對象,變量obj自己不持有該對象

    id obj1 = [NSMutableArray array];
    id obj2 = [NSDictionary dictionary];

    2.2 經過retain方法,非經過alloc new copy mutableCopy生成的對象,能夠成爲本身持有的對象

    id obj = [NSMutableArray array];
    
    [obj retain];
  3. 再也不須要本身持有的對象時釋放

    • 3.1 釋放經過alloc new copy mutableCopy生成的對象,一旦不在須要,務必要使用release方法釋放

      id obj = [[NSObject alloc] init];
      
      [obj release];
    • 3.2 用retain方法持有的非本身生成的對象,一旦再也不須要,也必定要使用release釋放

      id obj = [NSMutableArray array];
      [obj retain];    // 經過retain方法持有對象
      [obj release];   // 在不須要時也要經過release方法釋放對象
    • 3.3 用某個方法生成對象,並將其做爲方法的返回值,這時咱們該如何處理

      • 3.3.1 經過alloc new copy mutableCopy 或其餘符合命名規則的方法生成的對象,只須要原封不動的返回就能讓調用方也持有該對象

        - (id)allocObject {
            id obj = [[NSObject alloc] init];
            return obj;
        }
        
        - (id)allocObjectWithObject:(id)obj {
            id object = [obj allocObject];
            return object;
        }
      • 3.3.2 若是持有非本身生成的對象,例如[NSMutableArray array]生成的對象,咱們要使用autorelease方法釋放

        注:命名規則:用來取得誰都不持有的對象的方法名不能以alloc new copy mutableCopy開頭

        - (id)object {  
             id obj = [NSMutableArray array];
             [obj autorelease];
             return obj;
        }
      • 3.3.3 autorelease方法:提供了這樣的功能,使對象在超出指定的生存範圍時自動並正確釋放(調用release方法)
        release和autorelease的區別

  4. 非本身持有的對象沒法釋放---注意如下兩點,若是發生這樣的狀況會致使程序崩潰

    • 4.1 經過alloc new copy mutableCopy方法或者經過retain方法持有的對象,一旦再也不須要時,必須進行釋放,除此以外其餘方法得到的對象絕對不能釋放,一旦釋放會形成程序崩潰

    • 4.2 本身持有的對象釋放後再次釋放,形成僵死對象,引發程序崩潰或在訪問廢棄的對象時崩潰

      id obj = [[NSObject alloc] init];
      [obj release]; 
      [obj release];   // 再次釋放
相關文章
相關標籤/搜索