天天看點

OC----記憶體管理

任何繼承了NSObject的對象,都需要記憶體管理, 但是對基本資料類型無效(不需要釋放) 原理:

  1. 每個對象内部都儲存了一個與之相關聯的整數,稱為引用計數器
  2. 當使用alloc、new或者copy建立一個對象時,對象的引用計數器被設定為1
  3. 給對象發送一條retain消息,可以使引用計數器值+1
  4. 給對象發送一條release消息,可以使引用計數器值-1
  5. 當一個對象的引用計數器值為0時,那麼它将被銷毀,其占用的記憶體被系統回收,OC也會自動向對象發送一條dealloc消息。一般會重寫dealloc方法,在這裡釋放相關資源。一定不要直接調用dealloc方法。
  6. 可以給對象發送retainCount消息獲得目前的引用計數器值

向對象發送某個消息,相當于調用某個方法。   記憶體管理原則:

  1. 誰建立,誰釋放(“誰污染,誰治理”)。如果通過alloc、new或(mutable)copy來建立一個對象,那麼你必須調用release或autorelease。換句話說,不是你建立的,就不用你去釋放。
  2. 一般來說,除了alloc、new或copy之外的方法建立的對象都被聲明了autorelease
  3. 誰retain,誰release。隻要你調用了retain,無論這個對象誰如何生成的,你都要調用release

  如果在某個對象方法中retain了另一個對象,需要在這個對象釋放的時候同時釋放retain的那個對象。   如果想要retain對象新的成員變量,先釋放掉舊的成員變量;在釋放掉舊的成員變量前要先判斷新傳遞進來的成員變量與原來的成員變量是否相同,如果不同則釋放掉舊的成員變量,如果相同則不release舊的成員變量,也不進行retain。   @property記憶體管理新特性: @property一般幫我們自動生成的setter方法是很簡單的方法,不能實作記憶體管理,例如:

-(void)setBook:(Book*) book{
  _book=book;
}      

是以我們一般需要自己去實作book的setter方法,例如:

-(void)setBook:(Book *)book{
  if(_book!=book){
    [_book release];
     _book=[book retain];
   }
}      

  假如我們在某個類裡要使用很多個@property 語句去使用類的屬性的時候,如果還要自己在.m檔案中去寫setter方法會很麻煩,是以我們可以這麼寫: @property (retain)Book* book; @property (retain)Card* card; 這裡的retain代表:release舊的值,retain新的值 這樣相當于我們在.m檔案中實作了帶有記憶體管理的setter方法(即上面的代碼)   @property的其他參數:預設是(readwrite)屬性,同時生成get和set方法 @property(assign)int age;這句跟@property int age等價,@property預設就是assign參數的 @property(readonly)int age;這句表示age是一個隻讀變量,表示隻生成get方法   @property 格式:@property(參數1,參數2) 類型 名字; 參數可有可無,比如: @property int age; @property (nonatomic,retain)UIButton* btn;   參數主要分為3類: 讀寫屬性:readwrite/readonly setter處理:assign/retain/copy 原子性:atomic/nonatomic    @property屬性預設為atomic,提供多線程安全

  • 在多線程環境下,原子操作是必要的,否則就有可能引起錯誤的結果
  • 加了atomic,setter/getter是一個原子操作。如果有多個線程同時調用setter的話,不會出現某一個線程執行setter全部語句之前,另一個線程開始執行setter的情況,相當于函數頭尾加了鎖一樣

  nonatomic代表方法不考慮線程安全問題:

  • nonatomic表示禁止多線程,變量保護,提高性能
  • atomic是OC使用的一種線程保護技術,防止在寫入未完成的時候被另外一個線程讀取,造成資料錯誤。而這種機制是耗費系統資源的,是以在iphone這種小型裝置上,如果沒有使用多線程間的通訊程式設計,那麼nonatomic是一個非常好的選擇
  • 如果不需要多線程支援的話,用nonatomic就夠了,另外由于不涉及鎖操作,是以它執行相對快點

  @property的setter處理: assign:預設類型,setter方法直接指派,而不進行retain操作 retain:setter方法release舊值,再retain新值 copy:setter方法release舊值,再copy新值(暫時先這麼了解,後續會有關于copy文法的新解釋   @property的讀寫屬性: readwrite:産生setter和getter readonly:隻産生簡單的getter,沒有setter   @property的其他用法: 例如:@property(nonatomic,getter=isRich)BOOL rich; //getter是用來指定getter方法的方法名,同理setter也可以這樣用   自動釋放池(autorelease pool)

  • 自動釋放池是OC裡面的之中記憶體自動回收機制,一般可以将一些(臨時)變量添加到自動釋放池中,統一回收釋放
  • 當自動釋放池銷毀時,池裡面的所有對象都會調用一次release方法
  • OC對象隻需要發送一條autorelease消息,就會把這個對象添加到最近的自動釋放池中(棧頂的釋放池)
  • autorelease實際上隻是把對release的調用延遲了(相當于延遲回收對象),對于每一次autorelease,系統隻是把該對象放入了目前的autorelease pool中,當該pool被釋放時,該pool中的所有對象會被調用renlease 
//autoreleasepool代表建立一個自動釋放池
@autoreleasepool{       

//使用自動釋放池:

//之前:

 Book* book =[[Book alloc] init];

 [student setBook:book];

 [book release];

 //現在:

 Book *book =[[[Book alloc] init] autorelease];

 [student setBook:book];

 //不用調用[book release] }

      靜态方法不需要自己釋放記憶體,我們在開發中會經常用到靜态方法,因為我們在實作靜态方法時,會把變量放到autorelease中這樣就不用我們自己去釋放記憶體了 另外:靜态方法不能通路對象的成員變量   autorelease pool注意:

  • 在ARC下,不能使用[[NSAutoreleasePool alloc] init],而應當使用@autoreleasepool
  • 不要把大量循環操作放到同一個NSAutoreleasePool之間,這樣會造成記憶體峰值的上升
  • 盡量避免對大記憶體使用該方法,對于這種延遲釋放機制,還是盡量少用
  • sdk中一般利用靜态方法建立并傳回的對象都是已經autorelease的,不需要再進行release操作,如[NSNumber numberWithInt:10];傳回的對象是不需要再release的。但是通過[[NSNumber alloc] initWithInt:10]建立的對象需要release

轉載于:https://www.cnblogs.com/hqzxbb/p/4383749.html

繼續閱讀