我理解的objective-C內存管理

    我開始學習iOS的時候,已經有ARC這個東西了,因此一開始就是在ARC的環境下學習,雖然對於內存管理有了解,但並沒認真去處理這方面的問題。工做中的項目是之前開始開發,使用的是非ARC,並且項目已經初步成型,很差改爲ARC,因此我又回頭去研究內存管理。開始時很暈,不知那些地方改retain、那些地方該release,不事後來清楚了 許多,並且感受挺喜歡這些東西,感受對於程序的運行對了一個角度的認識,以爲很不錯。之後新建項目,估計不多會不用ARC,只是以爲內存管理仍是挺有意思的,並且是本身用心研究了的,就總結下。json

    一、結構:學習

   從對象的角度來看整個程序,是一個嵌套的結構,首先是一個A,這個A的構建運行過程當中又會用到許多其餘的對象,而其餘的對象再又會用到一些其餘的對象,其實很像json的結構。爲何要先這樣去看程序呢?這樣能夠把整個程序當作是一個對象包含了許多其餘對象的結構,這樣內存管理就能夠分解爲兩部分:(1)須要釋放的對象釋放掉  (2)一個對象釋放的時候,它所用到得對象都改被釋放(除了某些還被其餘對象使用的對象)spa

    舉例說就是push到一個ViewController,而後再從那個ViewController返回,那麼這個viewController會釋放,這通常都不會出錯,可是這個Viewcontroller的成員變量都釋放了嗎?這個ViewController方法中構建的臨時對象都釋放了嗎?而後你可能在這個viewContrller裏面使用了一個自定義的對象,假設爲pruductCell,那麼當你把改釋放這個對象的地方都處理好了,就能夠再去看看它的.m文件,是否它使用的對象也釋放正確了。指針

    我以爲從這樣一個結構去檢查挺好的。code

   二、一個對象釋放的時候,它所用到得對象都改被釋放(除了某些還被其餘對象使用的對象):對象

    首先,對象的引用和釋放要遵循:你retain的你要release,不是你retain的不要release(假設爲準則1)內存

 一個對象(假設爲A)使用到的其餘對象,能夠分爲兩類:一個是臨時對象(假設爲B),用完就能夠釋放;還一個是對象的屬性、成員變量(假設爲C),這個通常都會在對象A各個方法中被重複用到,這樣就能夠等到對象A被釋放的時候再釋放,也就是在A的dealloc方法裏面釋放。開發

    臨時對象:rem

 這個很好處理,用完了就釋放掉:字符串

UIView * subView = [[UIView alloc]initWithFrame:CGRectMake(30, 100, 150, 260)];
    [self.view addSubview:subView]; //addsubView會retain子視圖
    [subView release];
這裏說的釋放不是值釋放內存,是指釋放掉對這個臨時對象的擁有權,就是執行release。對於擁有權,個人理解是對象A對某個對象(假設爲B)進行了retain(包括alloc、copy等),這樣其它引用了這個對象的 對象(假設爲C),只要遵循準則1,當對象C release了對象B以後,對象B又會回到以前的引用計數。這樣只要對象A不release對象B,B的內存就永遠不會釋放。這就像對象A是擁有了對象B。

   而對臨時對象release,這樣當引用它的對象也release它以後,它就沒有被任何對象擁有,內存就會被釋放,這樣恰好。例如這裏,當subView被從self.view上面移除後,基本就是不須要用這個subView的時候,這時它內存被釋放,恰好。

  由於臨時變量構建在方法裏,出了這個方法就這個指針就沒了,就無法釋放對它的全部權了,因此必須在方法結束前release。

  屬性、成員變量:

  爲了在對象(A)存在的整個過程當中,它的屬性、成員變量都活着,必須不能release,不然可能會引用計數爲0,從而致使下次用的時候它內存已經被釋放了,從而程序崩潰:

_subView = [[UIView alloc]initWithFrame:CGRectMake(30, 100, 150, 260)];
    [self.view addSubview:_subView];
    [_subView release];
    
    [_subView removeFromSuperview]; 
    
    NSLog(@"%@",_subView); //程序崩潰
不是說成員變量就不釋放,而是釋放了,下次再用就沒有了。而既然是成員變量、屬性,那麼就是會再多個方法裏面用到的,甚至會被其餘的類的對象使用,因此要保持它是「活的」。


 三、關於屬性定義時的關鍵詞retain、assign:

      使用屬性定義變量時,自帶set\get方法,若是在變量賦值的時候使用self.XXX = YYY來方式賦值,實際上是調用了set方法,而與內存管理有關的問題是:若是屬性定義時使用retain,set方法是:

-(void )setXXX:(UIView *)XXX{
    [XXX retain];
    [_XXX release];
    _XXX = XXX;
}
對新值會retain,對舊值會release,從而使得對傳入的YYY獲取擁有權,保證在self使用它期間,它的內存永不會被釋放掉。這也遵循準則1。而使用assign倒是簡單賦值,沒有retain\release的操做。

   若是屬性是assign或者乾脆沒有使用self.XXX進行賦值,那麼就不會retain賦值對象,那麼:

UIView * view1 = [[UIView alloc]initWithFrame:CGRectMake(30, 100, 150, 260)];
    _XXX = view1;
    [view1 release];
這裏不會崩潰,可是接下來_XXX就變成了殭屍指針了,它指向位置的內存被釋放了,這也是assgin脆弱的地方,因此須要較長時間對某個對象的使用,最好使用retain,保證引用計數不會爲0。

 四、關於autoRelease:

  首先類方法構建對象,返回值通常自帶autoRelease,使用時注意下。

  爲何要使用autoRelease,個人理解是延緩release。由於我構建的,因此我要釋放,可是若是我release了,這個對象內存就被釋放了,那不就白構建了嗎?能夠構建,而後把它給須要使用的地方,而後再釋放。好比帶放回值得方法:

-(NSString *)createString{
    NSString * str = [[NSString alloc]init];
    return str;
}
若是我在方法裏面不釋放,而後外面使用的時候遵循準則1,那麼最後這個str的引用計數會保持在1,不會被釋放,這樣很成問題。可是若是釋放了,那return的就是空值,沒意義了。 autoRelease使用了,就能夠return一個有意義的值,而後最後這個對象在自動釋放池裏能被釋放,不用擔憂內存泄露。

 五、特殊的方法和對象:

   addSubview會對添加進來的視圖retain,NSMutableArray的adObject也會retain添加的對象,block會對裏面使用到的變量所有retain,極可能形成循環引用,NStimer在沒有釋放的時候,會retain構建是指定的target,想要釋放掉target,就須要先中止NSTimer。

   字符串常量不須要咱們管理內存。

相關文章
相關標籤/搜索