天天看點

Object C學習筆記4-記憶體管理

  Object-C的記憶體管理和.NET有些不一樣,.NET的記憶體回收機制是使用GC自動處理回收,而Object-C本質上還是C語言,是以很多時候還是需要手動去管理記憶體回收。

  1. Object-C生成一個對象

    Engine *en=[[Engine alloc] init];

    [en dealloc];

    Object-C對象生成配置設定空間在堆上,需要使用指針來指向其引用。前面也說到了,Object-C中得對象其實就是C中的指針。

  2. 對象初始化以及銷毀方法

    +(id) alloc; 注意這裡的alloc是一個類方法,調用alloc方法之後會在記憶體中配置設定一塊空間,并且引用計數會設定為1

    +(id) init; 調用init方法表示初始化對象

    -(void) dealloc; 這裡注意一下dealloc不是一個類方法,而是一個執行個體方法。dealloc 方法用于銷毀對象,當引用計數為0的時候系統會自動調用dealloc方法銷毀對象

    -(void) release; 調用這個方法用于釋放對象的引用,引用計數會-1

    -(void) retain ;調用這個方法用于将引用計數+1

    - (NSUInteger)retainCount; 用于擷取一個對象目前被多少對象擁有

  3. 叫苦不疊的記憶體洩露

    執行個體一: 

Object C學習筆記4-記憶體管理
Object C學習筆記4-記憶體管理

執行個體一 代碼

    [en print]; 這段代碼能夠正确的輸出資料;[en2 print] 和 [en2 dealloc] 方法則不能正常執行。因為en,en2 指針都指向了同一個對象引用,而[en dealloc]調用釋放了這個對象。當en2 調用print 和 dealloc的時候,該對象已經不存在了。

    執行個體二:

Object C學習筆記4-記憶體管理
Object C學習筆記4-記憶體管理

執行個體二 代碼

    [en print]這段代碼能夠正常的輸出資料,而[en2 print]仍然不能正常執行。為什麼?當調用[[Engine alloc ] init] 的時候,en 指針指向這個對象,這個時候retainCount=1 。

    Engine *en2=en 這個時候将指針en2也指向這個對象,retainCount=1;

    當en調用release方法的時候,retainCount 數量-1,retainCount=0; 這個時候系統會自動調用dealloc方法,自動回收對象。是以當下面再次調用的時候則不能正常執行。

    執行個體三:

Object C學習筆記4-記憶體管理
Object C學習筆記4-記憶體管理

執行個體三 代碼

    這段代碼和上面一段代碼的差別在于調用了[en2 retain]. 在Object-C中retainCount不會自動增加,需要調用retain才會增加。是以當調用[en2 retain]之後retainCount=2. 即使後面調用了[en release],retainCount仍然為1,對象不會去銷毀。是以下面會正常執行。如果不調用[en2 release]那麼retainCount會始終等于1,對象不會得到釋放就會發生記憶體洩露。

  4. 記憶體自動回收處理

   上面的處理的确有點太麻煩了,記憶體管理簡直就是噩夢。隻要稍微不注意就記憶體洩露了。現在還有更好的一種方式解決以上問題,那就是autorelease pool(自動釋放對象池)。使用自動釋放對象池,在某些情況一下可以不用手工去處理對象記憶體的釋放,貌似和.NET中的垃圾回收機制有點類似了,但是我們不要完全的依賴與它,這和自動管理記憶體還是有一定差距的。

Object C學習筆記4-記憶體管理
Object C學習筆記4-記憶體管理

自動釋放對象池

  看到上面的代碼,en 并沒有顯示去調用release方法。而autorelase pool 就是有這樣的一個好處。

  5. 自動回收原理簡介

  要使用自動回收我們必須手工建立自動釋放對象池,NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  NSAutoreleasePool内部包含一個數組(NSMutableArray),用來儲存聲明為autorelease的所有對象。如果一個對象聲明為autorelease,系統所做的工作就是把這個對象加入到這個數組中去。當NSAutoreleasePool自身釋放的時候,會周遊數組中的所有對象,并且調用release方法。如果對象的retainCount=0 那麼系統會釋放這些對象,如果retainCount>0,則會記憶體洩露。

  在某些情況下,NSAutoreleasePool 調用的銷毀方法比較遲,這個時候會占用大量的記憶體,我們也可以使用内嵌的方式,建立多個NSAutorelease的執行個體,讓占用的資源立馬釋放掉。

繼續閱讀