內(nèi)存管理機(jī)制簡(jiǎn)述

原理:
  • 每個(gè)對(duì)象內(nèi)部都保存了一個(gè)與之相關(guān)聯(lián)的整數(shù),稱為引用計(jì)數(shù)器(auto reference count)
  • 每當(dāng)使用alloc、new或者copy創(chuàng)建一個(gè)對(duì)象時(shí),對(duì)象的引用計(jì)數(shù)器被設(shè)置為1
  • 給對(duì)象發(fā)送一條retain消息(即調(diào)用retain方法),可以使引用計(jì)數(shù)器值+1
  • 給對(duì)象發(fā)送一條release消息,可以使引用計(jì)數(shù)器值-1
  • 當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)器值為0時(shí),那么它將被銷毀,其占用的內(nèi)存被系統(tǒng)回收,OC也會(huì)自動(dòng)向?qū)ο蟀l(fā)送一條dealloc消息。一般會(huì)重寫dealloc方法,在這里釋放相關(guān)資源。一定不要直接調(diào)用dealloc方法。
  • 可以給對(duì)象發(fā)送retainCount消息獲得當(dāng)前的引用計(jì)數(shù)器值。
基本原則:

MRC:

  • 內(nèi)存管理遵循“誰(shuí)創(chuàng)建,誰(shuí)釋放,誰(shuí)引用,誰(shuí)管理”的機(jī)制,當(dāng)通過(guò)alloc、new或者(mutable)copy來(lái)創(chuàng)建一個(gè)對(duì)象,必須調(diào)用release或autorelease(autorelease是延遲釋放內(nèi)存,不用你自己去手動(dòng)釋放,系統(tǒng)會(huì)知道在什么時(shí)候該去釋放掉它。),當(dāng)通過(guò)retain引用一個(gè)對(duì)象的時(shí)候,需要調(diào)用release。當(dāng)對(duì)象引用計(jì)數(shù)為0時(shí),系統(tǒng)將釋放該對(duì)象,這是OC的手動(dòng)管理內(nèi)存機(jī)制。

ARC:

  • iOS 5.0之后引用自動(dòng)管理機(jī)制——自動(dòng)引用計(jì)數(shù),管理機(jī)制與手動(dòng)機(jī)制一樣,只是不再需要調(diào)用retain、release、autorelease;它編譯時(shí)的特性,當(dāng)你使用ARC時(shí),在適當(dāng)位置插入release和autorelease;它引用strong和weak關(guān)鍵字,strong修飾的指針變量指向?qū)ο髸r(shí),當(dāng)指針指向新值或者指針不復(fù)存在,相關(guān)聯(lián)的對(duì)象就會(huì)自動(dòng)釋放,而weak修飾的指針變量指向?qū)ο螅?dāng)對(duì)象的擁有者指向新值或者不存在時(shí)weak修飾的指針會(huì)自動(dòng)置為nil。
  • 如果使用alloc、copy(mutableCopy)或者retian一個(gè)對(duì)象時(shí),你就有義務(wù),向它發(fā)送一條release或者autorelease消息。其他方法創(chuàng)建的對(duì)象,不需要由你來(lái)管理內(nèi)存。
  • 向一個(gè)對(duì)象發(fā)送一條autorelease消息,這個(gè)對(duì)象并不會(huì)立即銷毀,而是將這個(gè)對(duì)象放入了自動(dòng)釋放池,待池子釋放時(shí),它會(huì)向池中每一個(gè)對(duì)象發(fā)送一條release消息,以此來(lái)釋放對(duì)象。
  • 向一個(gè)對(duì)象發(fā)送release消息,并不意味著這個(gè)對(duì)象被銷毀了,而是當(dāng)這個(gè)對(duì)象的引用計(jì)數(shù)為0時(shí),系統(tǒng)才會(huì)調(diào)用dealloc方法,釋放該對(duì)象和對(duì)象本身它所擁有的實(shí)例。
注意事項(xiàng):
  • 如果一個(gè)對(duì)象有一個(gè)strong類型的指針指向著,這個(gè)對(duì)象就不會(huì)被釋放。如果一個(gè)指針指向超出了它的作用域,就會(huì)被指向nil。如果一個(gè)指針被指向nil,那么它原來(lái)指向的對(duì)象就被釋放了。當(dāng)一個(gè)視圖控制器釋放時(shí),它內(nèi)部的全局指針會(huì)被指向nil。
  • 局部變量:出了作用域,指針會(huì)被置為nil。
  • 方法內(nèi)部創(chuàng)建對(duì)象,外部使用需要添加autorelease。
  • Xib連線的時(shí)候,用weak修飾。
  • 代理MRC使用assign修飾,ARC使用weak修飾。
  • block使用copy修飾。
  • block中為了避免循環(huán)引用(常見(jiàn)self持有的block)問(wèn)題,使用__weak方式。
  • 聲明屬性時(shí),不要以new開(kāi)頭。如果非要以new開(kāi)頭命名屬性的名字,需要自己定制get方法名,如:
    @property(getter = theString) NSString *newString;
  • 如果要使用自動(dòng)釋放池,用@autoreleasepool{} 。
  • ARC只能管理Foundation框架的變量,如果程序中把Foundation中的變量強(qiáng)制換成COre Foundation中的變量需要交換管理權(quán)。
  • 在非ARC工程中采用ARC去編譯某些類:-fobjc-arc。
  • 在ARC下的工程采用非ARC去編譯某些類:-fno-fobjc-arc。
MRC內(nèi)存管理測(cè)試:
Student類:
@interface Student : NSObject {  
    int age;  
}  
@property int age;  
@end 

@implementation Student  
@synthesize age;  
//重寫dealloc方法,當(dāng)引用計(jì)數(shù)器(auto reference count)為零的時(shí)候調(diào)用。  
- (void)dealloc {  
    NSLog(@"%@被銷毀了",self);  
    [super dealloc]; 
}  
@end  

Controller類:
Student *stu = [[Student alloc]init];// alloc一次,引用計(jì)數(shù)器為1  
// Student *stu = [[[Studnet alloc]init] autorelease];// 這樣寫的話系統(tǒng)會(huì)在適當(dāng)?shù)牡胤綄?duì)stu的內(nèi)存進(jìn)行自動(dòng)回收,就不用自己寫release回收了
// z代表無(wú)符號(hào)  
NSLog(@"count:%zi", [stu retainCount]);  
[stu retain];// 引用計(jì)數(shù)器變?yōu)?  
NSLog(@"count:%zi", [stu retainCount]);  
[stu release];// 引用計(jì)數(shù)器變?yōu)?  
NSLog(@"count:%zi", [stu retainCount]);          
[stu release];// release一次,引用計(jì)數(shù)器減1,變?yōu)?然后會(huì)調(diào)用dealloc方法

運(yùn)行結(jié)果:
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] count:2
2017-04-20 23:51:51.041 **[93035:36023785] count:1
2017-04-20 23:51:51.041 **[93035:36023785] <Student: 0x100109a80>被銷毀了

------隨筆

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容