記憶體管理機制,ios記憶體管理機制
Objective-C中提供了兩種記憶體管理機制MRC(MannulReference Counting)和ARC(Automatic Reference Counting),分別提供對記憶體的手動和自動管理,來滿足不同的需求.
ARC:
ARC是Auto Reference Counting的縮寫,即自動引用計數,由編譯器在代碼合適的位置中自動添加retain/Release/Autorelease/dealloc方法從而進行記憶體管理.
ARC幾個要點:
- 在對象被建立時 retain count +1,在對象被release時 retain count -1.當retain count 為0 時,銷毀對象。
- 程式中加入autoreleasepool的對象會由系統自動加上autorelease方法,如果該對象引用計數為0,則銷毀。
那麼ARC是為瞭解決什麼問題誕生的呢?這個得追溯到MRC手動記憶體管理時代說起。
MRC下記憶體管理的缺點:
- 當我們要釋放一個堆記憶體時,首先要確定指向這個堆空間的指標都被release了。(避免提前釋放)
- 釋放指標指向的堆空間,首先要確定哪些指標指向同一個堆,這些指標只能釋放一次。(MRC下即誰建立,誰釋放,避免重複釋放)
- 模組化操作時,對象可能被多個模組建立和使用,不能確定最後由誰去釋放。
- 多線程操作時,不確定哪個線程最後使用完畢
在ARC中與記憶體管理有關的標識符,可以分為變數標識符(_strong, _weak, _unsafe_unretained, autoreleasing)和屬性標識符(nonatomic/atomic, assign/retain/strong/weak/unsafe_unretained/copy,readonly/readwrite),對於變數預設為__strong,而對於屬性預設為unsafe_unretained。也存在autoreleasepool。
其中assign/retain/copy與MRC下property的標識符意義相同,strong類似與retain,assign類似於unsafe_unretained,strong/weak/unsafe_unretained與ARC下變數標識符意義相同,只是一個用於屬性的標識,一個用於變數的標識(帶兩個下劃短線__)。所列出的其他的標識符與MRC下意義相同。
(1)對於assign,你可以對標量類型(如int)使用這個屬性。你可以想象一個float,它不是一個對象,所以它不能retain、copy。
(2)對於copy,指定應該使用對象的副本(深度複製),前一個值發送一條release訊息。基本上像retain,但是沒有增加引用計數,是分配一塊新的記憶體來放置它。特別適用於NSString,如果你不想改變現有的,就用這個,因為NSMutableString,也是NSString。
MRC:
在MRC的記憶體管理員模式下,與對變數的管理相關的方法有:retain,release和autorelease。retain和release方法操作的是引用記數,當引用記數為零時,便自動釋放記憶體。並且可以用NSAutoreleasePool對象,對加入自動釋放池(autorelease調用)的變數進行管理,當drain時回收記憶體。
Strong 和 Weak 的區別:
強引用持有對象,弱引用不持有對象。
強引用可以釋放對象,但弱引用不可以,因為弱引用不持有對象,當弱引用指向一個強引用所持有的對象時,當強引用將對象釋放掉後,弱引用會自動的被賦值為nil,即弱引用會自動的指向nil。
Strong 強引用,舉個例子:
1 id __strong test0 = [[NSObject alloc] init]; /* 設為對象A*/2 3 id __strong test1 = [[NSObject alloc] init];/*設為對象B*/
test0 和 test1 都是強引用,test0是對象A的持有人,就是擁有A,test1是對象B的持有人,就是擁有對象B,若:
test1 = test0;/*對象A的持有人就變成了test1*/
這樣對象B就沒有了持有人,沒有持有人的對象會被ARC回收,就是釋放,這樣:
test1持有對象A,test0也持有對象A。
weak 弱引用,主要作用是用來防治循環參考出現記憶體流失的問題,它主要是弱引用,弱引用就是不持有對象,只是指向這個對象,舉個例子:
1 id __strong test0 = [[NSObject alloc] init]; /* 設為對象A*/2 3 id __strong test1 = [[NSObject alloc] init];/*設為對象B*/4 5 id __weak test2 = test0;/*test1持有對象A的弱引用*/
test0持有對象A的強引用,而test2持有對象A的弱引用,也就是說,test0還是持有A的,而test2弱引用了test0的對象A,並沒有持有對象A,當test2離開了範圍,對對象A的引用就會失去,當對象A被釋放掉之後,test2會被置為nil,並不會出現crash。若:
test1 = test0;/*test1強引用對象A*/
此時對象B因為沒有持有人就會被釋放。
再如:
1 #import <Foundation/Foundation.h> 2 3 int main(int argc, const char * argv[]) { 4 @autoreleasepool { 5 id __weak obj0 = nil; 6 if (YES) { 7 id obj1 = [[NSObject alloc] init]; //預設為強引用,即為strong類型 8 obj0 = obj1; 9 NSLog(@"obj0: %@", obj0);10 }11 NSLog(@"obj0: %@", obj0);12 }13 return 0;14 }15 16 /*17 * 輸出結果18 * obj0: <NSObject: 0x1003066c0>19 * obj0: (null)20 *21 * 因為obj1產生的預設的為強引用(__strong),在超出if的範圍之後,obj1所持有的對象被釋放,22 * obj0為弱引用,所以obj0不持有對象,在obj1對象釋放後,obj0自動的被賦值為nil23 * 弱引用的特性是,不持有對象,即便是寫成id __weak obj1 = [[NSObject alloc] init];24 * 此代碼系統會給與警告,因為這裡obj1被聲明成弱引用,那麼在賦值之後,alloc出來的對象會被立即釋放。25 */