ios內(nèi)存管理原則

1.? 內(nèi)總管理原則(引用計(jì)數(shù))

IOS的對象都繼承于NSObject, ? 該對象有一個(gè)方法:retainCount ,內(nèi)存引用計(jì)數(shù)。 引用計(jì)數(shù)在很多技術(shù)都用到: window下的COM組件,多線程的信號量,讀寫鎖,思想都一樣。

(一般情況下: 后面會討論例外情況)

alloc ? ? ?對象分配后引用計(jì)數(shù)為1

retain ? ?對象的引用計(jì)數(shù)+1

copy ? ? ?copy 一個(gè)對象變成新的對象(新內(nèi)存地址) 引用計(jì)數(shù)為1 原來對象計(jì)數(shù)不變

release ? ? ? ? ? ?對象引用計(jì)數(shù)-1 如果為0釋放內(nèi)存

autorelease ? ? ?對象引用計(jì)數(shù)-1 如果為0不馬上釋放,最近一個(gè)個(gè)pool時(shí)釋放

NSLog(@"sMessage retainCount:%u",[sMessageretainCount]);

[sMessageretain]; //2

NSLog(@"sMessage retainCount:%u",[sMessageretainCount]);

NSLog(@"sMessage retainCount:%u",[sMessageretainCount]);

NSLog(@"sMessage retainCount:%u",[sMessageretainCount]);

內(nèi)存管理的原則就是最終的引用計(jì)數(shù)要平衡,

如果最后引用計(jì)數(shù)大于0 ?則會內(nèi)存泄露

如果引用 計(jì)數(shù)等于0還對該對象進(jìn)行操作,則會出現(xiàn)內(nèi)存訪問失敗,crash ? ?所以盡量設(shè)置為nil

這兩個(gè)問題都很嚴(yán)重,所以請一定注意內(nèi)存釋放和不用過后設(shè)置為nil

2. autoReleasePool

每個(gè)工程都有一個(gè) main.m 文件: 內(nèi)容如下:

int main(int argc, char *argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

int retVal = UIApplicationMain(argc, argv, nil, nil);

[pool release];

return retVal;

}

很明顯C語言的main 函數(shù):

NSAutoreleasePool 是用來做autorelease 變量釋放的,前面說了, autorelease不會馬上釋放,當(dāng)他到了最近的pool release 時(shí)會檢查reatin count 是不是為0, 為0就釋放。

當(dāng)我們在一段代碼時(shí)加入了大量的autorelease變量時(shí),我們應(yīng)該為這段代碼加上

Autoreleasepool,其它時(shí)候不用

在返回一個(gè)對象時(shí)常常要返回一個(gè)autorelease 對象,因?yàn)閛bjectC 對象都是動態(tài)內(nèi)存,沒有

棧的概念,所以不能像C/C++一樣返回一個(gè)對象到棧,只能用autorelease對象。

3. 成員變量與屬性

實(shí)際情況并非上面那么簡單,你可能需要在一個(gè)函數(shù)里調(diào)用另一個(gè)函數(shù)分配的變量這時(shí)候

有兩個(gè)選擇: ?類成員變量和使用屬性

@interface TestMem: NSObject {

TestObject ? *m_testObject?; ? ? ? ? ? ?// 成員變量

TestObject ? *testObject; ? ? ? ? ? ? ? ? //成員變量

}

成員變量與上面的內(nèi)存管理是一致的,只是在不同的函數(shù)里要保持引用計(jì)數(shù)加減的平衡

所以要你要每次分配的時(shí)候檢查是否上次已經(jīng)分配了。是否還能調(diào)用

什么時(shí)候用屬性?

1. 把成員做為public.

2. outlet 一般聲明為屬性( 這個(gè)內(nèi)存于系統(tǒng)控制,但我們還是應(yīng)該做一樣操作,后面會講)

3. 如果很多函數(shù)都需要改變這個(gè)對象 ,或這個(gè)函數(shù)會觸發(fā)很多次,建議使用屬性。我們看看屬性函數(shù)展開后是什么樣子:

// assign

-(void)setTestObject :(id)newValue{

testObject= newValue;

}

// retain

-(void)setTestObject ?:(id)newValue{

if (testObject!= newValue) {

[testObject release];

testObject= [newValue retain];

}

}

// copy

-(void)setTestObject :(id)newValue{

if (testObject?!= newValue) {

[testObject?release];

testObject?= [newValue copy];

}

}

asssign 相于于指針賦值,不對引用計(jì)數(shù)進(jìn)行操作,注意原對象不用了,一定要把這個(gè)設(shè)置為nil

retain 相當(dāng)于對原對象的引用計(jì)數(shù)加1

copy 不對原對象的引用計(jì)數(shù)改變,生成一個(gè)新對象引用計(jì)數(shù)為1

注意:

self.testObject 左值調(diào)用的是setTestObject 方法. 右值為get方法,get 方法比較簡單不用說了

而 真接testObject 使用的是成員變量

self.testObject = [[testObject alloc] init]; ? // 錯(cuò) ?reatin 兩次

testObject = ? [NSArray objectbyindex:0];//錯(cuò)不安全,沒有retain 后面release會出錯(cuò)

如果testObject已有值也會mem leak

4. 自動管理對象

IOS 提供了很多static(+) 創(chuàng)建對象的類方法,這些方面是靜態(tài)的,可以直接用類名

調(diào)用如:

NSString *testString = [NSString stringWithFormat:@"test" ];

testString 是自動管理的對象,你不用relese 他,他有一個(gè)很大的retain count,?release后數(shù)字不變。

5. 例外

有一些通過alloc 生成的對象相同是自動管理的如:

NSString ?*testString ?= [[NSString alloc]?initWithString:@"test1"];

retain count 同樣是很大的數(shù),沒辦法release

但為了代碼對應(yīng),還是應(yīng)該加上[ testString release];

不然xcode的Analyze 會認(rèn)識內(nèi)存leak, 但I(xiàn)nstruments leak 工具檢測是沒有的

6.view ?內(nèi)存管理

通常我們編程會用到view, ? 在view 中的方法:

viewDidload

didReceiveMemoryWarning

viewDidUnload

@property (retain) NSArray *iarrTestMem

viewDidLoad

init retain is ? ? ? ? 0

(alloc) ? ? ? ? ? ? ? +1=1

if(memwarning)

didrecivememwarning ?-0=1

didviewunload ? ? ? ?-1

=0

will loadviewDidLoad when next load view

esle

dealloc: ? ? ? ? ? ? -1

=0

我們來看一個(gè)變量的生命周期

當(dāng)view被alloc

A. 框架會自動調(diào)用viewDidLoad

一般來說在viewDidLoad 中分配變量:

假設(shè)為alloc 現(xiàn)在變量的reatin 為 0 +1 = 1;

第一種情況:

B. 如果這時(shí)候view被釋放,會調(diào)用 dealloc,

這時(shí)候我們應(yīng)該在dealloc里release 這個(gè)變量現(xiàn)在為0

第二種情況:

B. 這時(shí)候view被換到下層,如navigation的上級,不可顯示狀態(tài):如果

系統(tǒng)內(nèi)存吃緊: 系統(tǒng)會發(fā) 消息,我們的didrecivememwarning 函數(shù)

被調(diào)用 ,該函數(shù)是提醒我們應(yīng)該釋放一些現(xiàn)在用不上的東西,特別是一些較大的

如圖片,cache 數(shù)據(jù)等, 注意如果在這里釋放了,代碼在用的地方要進(jìn)行

判斷,是否需要重新加載

C. 他會調(diào)用didviewunload

這時(shí)候我們要注意了,因?yàn)樗{(diào)用了didviewunload,在下次這個(gè)view被顯示的時(shí)候

會再次調(diào)用didviewload, 我們在didviewload里分配的孌童就會被分配兩次,所以我

們在這里一定要釋放didview里分配的變量,不管直接分配的還是間接分配的,

如發(fā)消息給其它函數(shù)分配的。 那我們在下次分配之前釋放一次行不行, 不行,因?yàn)檫@

時(shí)候內(nèi)存吃緊了,你應(yīng)該多釋放內(nèi)存,不然你的程序可能會被系統(tǒng)kill. 還有雖然對

[xxx release] ?對nil 發(fā) release 是沒問題的,但邏輯上讓人覺得很奇怪,以為在別的

地方分配過。 所以這里應(yīng)該釋放內(nèi)存,

如果你是一個(gè)屬性,用:

self.xxx = nil 比較好,他相當(dāng)于幫你釋放了原來的,還把xxx設(shè)置為了nil.

如果不是一個(gè)屬性 :也最好把xxx= nil. ?這樣比較安全。如果這個(gè)view不再被換入

下一步直接調(diào)用 dealloc, 這時(shí)候你的dealloc里的[xxx release], 如果這里的xxx不為nil你在

didviewunload里release 了,就非常危險(xiǎn)

D. 如果這時(shí)候view被釋放,會調(diào)用 dealloc,

這時(shí)候我們應(yīng)該在dealloc里release

前面我們說了outlet的內(nèi)存沒辦法管理(看下生命周期)

@property (nonatomic,retain) IBOutlet UILabel *ilblTestMem;

init retain is 2

didviewLoad:

= 2

if(memwarning)

memwaring ? ? ? - retain count -1

= 1

viewdidunload: ? -1

=0

will loadviewDidLoad when next load view

else

dealloc: ? ? ? ? -1

=1

第一種情況

A. didviewLoad:

retain count 為2

B. ?dealloc:

-1 ? retain count 為1

第二種情況:

B. ? memwarning

系統(tǒng)會把 retain count 減到1

C. ? viewdidunload

我們應(yīng)該release 一次 這樣 retain count 到0,變量會馬上dealloc,更快的釋放內(nèi)存

注意用 self.ilblTestMem = nil ?設(shè)置為nil, ?為 dealloc 做準(zhǔn)備

D. ?dealloc:

-1

NSObject*sMessage = [[NSObjectalloc]init]; //1

[sMessagerelease]; //1

NSLog(@"sMessage retainCount:%u",[sMessageretainCount]);

[sMessagerelease]; //0

//not crash ?(retainCount also can call)

//crash ?(can not call)

[sMessagerelease];

@property (nonatomic, retain)?TestObject ?testObject*;//為testObject成員變量生成屬性方法

@end

iPhone/Mac?Objective-C內(nèi)存管理教程和原理剖析

前言

初學(xué)objectice-C的朋友都有一個(gè)困惑,總覺得對objective-C的內(nèi)存管理機(jī)制琢磨不透,程序經(jīng)常內(nèi)存泄漏或莫名其妙的崩潰。我在這里總結(jié)了自己對objective-C內(nèi)存管理機(jī)制的研究成果和經(jīng)驗(yàn),寫了這么一個(gè)由淺入深的教程。希望對大家有所幫助,也歡迎大家一起探討。

此文涉及的內(nèi)存管理是針對于繼承于NSObject的Class。

一基本原理

Objective-C的內(nèi)存管理機(jī)制與.Net/Java那種全自動的垃圾回收機(jī)制是不同的,它本質(zhì)上還是C語言中的手動管理方式,只不過稍微加了一些自動方法。

1Objective-C的對象生成于堆之上,生成之后,需要一個(gè)指針來指向它。

ClassA *obj1 = [[ClassA alloc] init];

2Objective-C的對象在使用完成之后不會自動銷毀,需要執(zhí)行dealloc來釋放空間(銷毀),否則內(nèi)存泄露。

[obj1 dealloc];

這帶來了一個(gè)問題。下面代碼中obj2是否需要調(diào)用dealloc?

ClassA *obj1 = [[ClassA alloc] init];

ClassA *obj2 = obj1;

[obj1 hello]; //輸出hello

[obj1 dealloc];

[obj2 hello]; //能夠執(zhí)行這一行和下一行嗎?

[obj2 dealloc];

不能,因?yàn)閛bj1和obj2只是指針,它們指向同一個(gè)對象,[obj1 dealloc]已經(jīng)銷毀這個(gè)對象了,不能再調(diào)用[obj2 hello]和[obj2 dealloc]。obj2實(shí)際上是個(gè)無效指針。

如何避免無效指針?請看下一條。

3Objective-C采用了引用計(jì)數(shù)(ref count或者retain count)。對象的內(nèi)部保存一個(gè)數(shù)字,表示被引用的次數(shù)。例如,某個(gè)對象被兩個(gè)指針?biāo)赶颍ㄒ茫┠敲此膔etain count為2。需要銷毀對象的時(shí)候,不直接調(diào)用dealloc,而是調(diào)用release。release會讓retain count減1,只有retain count等于0,系統(tǒng)才會調(diào)用dealloc真正銷毀這個(gè)對象。

ClassA *obj1 = [[ClassA alloc] init]; //對象生成時(shí),retain count = 1

[obj1 release]; //release使retain count減1,retain count = 0,dealloc自動被調(diào)用,對象被銷毀

我們回頭看看剛剛那個(gè)無效指針的問題,把dealloc改成release解決了嗎?

ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1

ClassA *obj2 = obj1; //retain count = 1

[obj1 hello]; //輸出hello

[obj1 release]; //retain count = 0,對象被銷毀

[obj2 hello];

[obj2 release];

[obj1 release]之后,obj2依然是個(gè)無效指針。問題依然沒有解決。解決方法見下一條。

4Objective-C指針賦值時(shí),retain count不會自動增加,需要手動retain。

ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1

ClassA *obj2 = obj1; //retain count = 1

[obj2 retain]; //retain count = 2

[obj1 hello]; //輸出hello

[obj1 release]; //retain count = 2 – 1 = 1

[obj2 hello]; //輸出hello

[obj2 release]; //retain count = 0,對象被銷毀

問題解決!注意,如果沒有調(diào)用[obj2 release],這個(gè)對象的retain count始終為1,不會被銷毀,內(nèi)存泄露。(1-4可以參考附件中的示例程序memman-no-pool.m)

這樣的確不會內(nèi)存泄露,但似乎有點(diǎn)麻煩,有沒有簡單點(diǎn)的方法?見下一條。

5Objective-C中引入了autorelease pool(自動釋放對象池),在遵守一些規(guī)則的情況下,可以自動釋放對象。(autorelease pool依然不是.Net/Java那種全自動的垃圾回收機(jī)制)

5.1新生成的對象,只要調(diào)用autorelease就行了,無需再調(diào)用release!

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1但無需調(diào)用release

5.2對于存在指針賦值的情況,代碼與前面類似。

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1

ClassA *obj2 = obj1; //retain count = 1

[obj2 retain]; //retain count = 2

[obj1 hello]; //輸出hello

//對于obj1,無需調(diào)用(實(shí)際上不能調(diào)用)release

[obj2 hello]; //輸出hello

[obj2 release]; //retain count = 2-1 = 1

細(xì)心的讀者肯定能發(fā)現(xiàn)這個(gè)對象沒有被銷毀,何時(shí)銷毀呢?誰去銷毀它?(可以參考附件中的示例程序memman-with-pool.m)請看下一條。

6autorelease pool原理剖析。(其實(shí)很簡單的,一定要堅(jiān)持看下去,否則還是不能理解Objective-C的內(nèi)存管理機(jī)制。)

6.1autorelease pool不是天生的,需要手動創(chuàng)立。只不過在新建一個(gè)iphone項(xiàng)目時(shí),xcode會自動幫你寫好。autorelease pool的真名是NSAutoreleasePool。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

6.2NSAutoreleasePool內(nèi)部包含一個(gè)數(shù)組(NSMutableArray),用來保存聲明為autorelease的所有對象。如果一個(gè)對象聲明為autorelease,系統(tǒng)所做的工作就是把這個(gè)對象加入到這個(gè)數(shù)組中去。

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此對象加入autorelease pool中

6.3NSAutoreleasePool自身在銷毀的時(shí)候,會遍歷一遍這個(gè)數(shù)組,release數(shù)組中的每個(gè)成員。如果此時(shí)數(shù)組中成員的retain count為1,那么release之后,retain count為0,對象正式被銷毀。如果此時(shí)數(shù)組中成員的retain count大于1,那么release之后,retain count大于0,此對象依然沒有被銷毀,內(nèi)存泄露。

6.4默認(rèn)只有一個(gè)autorelease pool,通常類似于下面這個(gè)例子。

int main (int argc, const char *argv[])

{

NSAutoreleasePool *pool;

pool = [[NSAutoreleasePool alloc] init];

// do something

[pool release];

return (0);

} // main

所有標(biāo)記為autorelease的對象都只有在這個(gè)pool銷毀時(shí)才被銷毀。如果你有大量的對象標(biāo)記為autorelease,這顯然不能很好的利用內(nèi)存,在iphone這種內(nèi)存受限的程序中是很容易造成內(nèi)存不足的。例如:

int main (int argc, const char *argv[])

{

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

int i, j;

for (i = 0; i < 100; i++ )

{

for (j = 0; j < 100000; j++ )

[NSString stringWithFormat:@"1234567890"];//產(chǎn)生的對象是autorelease的。

}

[pool release];

return (0);

} // main

(可以參考附件中的示例程序memman-many-objs-one-pool.m,運(yùn)行時(shí)通過監(jiān)控工具可以發(fā)現(xiàn)使用的內(nèi)存在急劇增加,直到pool銷毀時(shí)才被釋放)你需要考慮下一條。

7Objective-C程序中可以嵌套創(chuàng)建多個(gè)autorelease pool。在需要大量創(chuàng)建局部變量的時(shí)候,可以創(chuàng)建內(nèi)嵌的autorelease pool來及時(shí)釋放內(nèi)存。(感謝網(wǎng)友hhyytt和neogui的提醒,某些情況下,系統(tǒng)會自動創(chuàng)建autorelease pool,請參見第四章)

int main (int argc, const char *argv[])

{

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

int i, j;

for (i = 0; i < 100; i++ )

{

NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];

for (j = 0; j < 100000; j++ )

[NSString stringWithFormat:@"1234567890"];//產(chǎn)生的對象是autorelease的。

[loopPool release];

}

[pool release];

return (0);

} // main

二口訣與范式

1口訣。

1.1誰創(chuàng)建,誰釋放(類似于“誰污染,誰治理”)。如果你通過alloc、new或copy來創(chuàng)建一個(gè)對象,那么你必須調(diào)用release或autorelease。換句話說,不是你創(chuàng)建的,就不用你去釋放。

例如,你在一個(gè)函數(shù)中alloc生成了一個(gè)對象,且這個(gè)對象只在這個(gè)函數(shù)中被使用,那么你必須在這個(gè)函數(shù)中調(diào)用release或autorelease。如果你在一個(gè)class的某個(gè)方法中alloc一個(gè)成員對象,且沒有調(diào)用autorelease,那么你需要在這個(gè)類的dealloc方法中調(diào)用release;如果調(diào)用了autorelease,那么在dealloc方法中什么都不需要做。

1.2除了alloc、new或copy之外的方法創(chuàng)建的對象都被聲明了autorelease。

1.3誰retain,誰release。只要你調(diào)用了retain,無論這個(gè)對象是如何生成的,你都要調(diào)用release。有時(shí)候你的代碼中明明沒有retain,可是系統(tǒng)會在默認(rèn)實(shí)現(xiàn)中加入retain。不知道為什么蘋果公司的文檔沒有強(qiáng)調(diào)這個(gè)非常重要的一點(diǎn),請參考范式2.7和第三章。

2范式。

范式就是模板,就是依葫蘆畫瓢。由于不同人有不同的理解和習(xí)慣,我總結(jié)的范式不一定適合所有人,但我能保證照著這樣做不會出問題。

2.1創(chuàng)建一個(gè)對象。

ClassA *obj1 = [[ClassA alloc] init];

2.2創(chuàng)建一個(gè)autorelease的對象。

ClassA *obj1 = [[[ClassA alloc] init] autorelease];

2.3Release一個(gè)對象后,立即把指針清空。(順便說一句,release一個(gè)空指針是合法的,但不會發(fā)生任何事情)

[obj1 release];

obj1 = nil;

2.4指針賦值給另一個(gè)指針。

ClassA *obj2 = obj1;

[obj2 retain];

//do something

[obj2 release];

obj2 = nil;

2.5在一個(gè)函數(shù)中創(chuàng)建并返回對象,需要把這個(gè)對象設(shè)置為autorelease

ClassA *Func1()

{

ClassA *obj = [[[ClassA alloc]init]autorelease];

return obj;

}

2.6在子類的dealloc方法中調(diào)用基類的dealloc方法

-(void) dealloc

{

[super dealloc];

}

2.7在一個(gè)class中創(chuàng)建和使用property。

2.7.1聲明一個(gè)成員變量。

ClassB *objB;

2.7.2聲明property,加上retain參數(shù)。

@property (retain) ClassB* objB;

2.7.3定義property。(property的默認(rèn)實(shí)現(xiàn)請看第三章)

@synthesize objB;

2.7.4除了dealloc方法以外,始終用.操作符的方式來調(diào)用property。

self.objB或者objA.objB

2.7.5在dealloc方法中release這個(gè)成員變量。

[objB release];

示例代碼如下(詳細(xì)代碼請參考附件中的memman-property.m,你需要特別留意對象是在何時(shí)被銷毀的。):

@interface ClassA : NSObject

{

ClassB* objB;

}

@property (retain) ClassB* objB;

@end

@implementation ClassA

@synthesize objB;

-(void) dealloc

{

[objB release];

[super dealloc];

}

@end

2.7.6給這個(gè)property賦值時(shí),有手動release和autorelease兩種方式。

void funcNoAutorelease()

{

ClassB *objB1 = [[ClassB alloc]init];

ClassA *objA = [[ClassA alloc]init];

objA.objB = objB1;

[objB1 release];

[objA release];

}

void funcAutorelease()

{

ClassB *objB1 = [[[ClassB alloc]init] autorelease];

ClassA *objA = [[[ClassA alloc]init] autorelease];

objA.objB = objB1;

}

三@property (retain)和@synthesize的默認(rèn)實(shí)現(xiàn)

在這里解釋一下@property (retain) ClassB* objB;和@synthesize objB;背后到底發(fā)生了什么(retain property的默認(rèn)實(shí)現(xiàn))。property實(shí)際上是getter和setter,針對有retain參數(shù)的property,背后的實(shí)現(xiàn)如下(請參考附件中的memman-getter-setter.m,你會發(fā)現(xiàn),結(jié)果和memman-property.m一樣):

@interface ClassA : NSObject

{

}

-(ClassB *) getObjB;

-(void) setObjB:(ClassB *) value;

@end

@implementation ClassA

-(ClassB*) getObjB

{

}

-(void) setObjB:(ClassB*) value

{

}

在setObjB中,如果新設(shè)定的值和原值不同的話,必須要把原值對象release一次,這樣才能保證retain count是正確的。

由于我們在class內(nèi)部retain了一次(雖然是默認(rèn)實(shí)現(xiàn)的),所以我們要在dealloc方法中release這個(gè)成員變量。

-(void) dealloc

{

}

四系統(tǒng)自動創(chuàng)建新的autorelease pool

在生成新的Run Loop的時(shí)候,系統(tǒng)會自動創(chuàng)建新的autorelease pool(非常感謝網(wǎng)友hhyytt和neogui的提醒)。注意,此處不同于xcode在新建項(xiàng)目時(shí)自動生成的代碼中加入的autorelease pool,xcode生成的代碼可以被刪除,但系統(tǒng)自動創(chuàng)建的新的autorelease pool是無法刪除的(對于無Garbage Collection的環(huán)境來說)。Objective-C沒有給出實(shí)現(xiàn)代碼,官方文檔也沒有說明,但我們可以通過小程序來證明。

在這個(gè)小程序中,我們先生成了一個(gè)autorelease pool,然后生成一個(gè)autorelease的ClassA的實(shí)例,再在一個(gè)新的run loop中生成一個(gè)autorelease的ClassB的對象(注意,我們并沒有手動在新run loop中生成autorelease pool)。精簡的示例代碼如下,詳細(xì)代碼請見附件中的memman-run-loop-with-pool.m。

{

[runLoop run]; //在新loop中調(diào)用一函數(shù),生成ClassB的autorelease實(shí)例

輸出如下:

create an autorelasePool

create an instance of ClassA and autorelease

create an instance of ClassB and autorelease

ClassB destroyed

releasing autorelasePool

ClassA destroyed

autorelasePool is released

注意在我們銷毀autorelease pool之前,ClassB的autorelease實(shí)例就已經(jīng)被銷毀了。

有人可能會說,這并不能說明新的run loop自動生成了一個(gè)新的autorelease pool,說不定還只是用了老的autorelease pool,只不過后來drain了一次而已。我們可以在main函數(shù)中不生成autorelease pool。精簡的示例代碼如下,詳細(xì)代碼請見附件中的memman-run-loop-without-pool.m。

{

[runLoop run]; //在新loop中調(diào)用一函數(shù),生成ClassB的autorelease實(shí)例

輸出如下:

No autorelasePool created

create an instance of ClassA

create an instance of ClassB and autorelease

ClassB destroyed

Manually release the instance of ClassA

ClassA destroyed

我們可以看出來,我們并沒有創(chuàng)建任何autorelease pool,可是ClassB的實(shí)例依然被自動銷毀了,這說明新的run loop自動創(chuàng)建了一個(gè)autorelease pool,這個(gè)pool在新的run loop結(jié)束的時(shí)候會銷毀自己(并自動release所包含的對象)。

補(bǔ)充說明

在研究retain count的時(shí)候,我不建議用NSString。因?yàn)樵谙旅娴恼Z句中,

NSString *str1 = @”constant string”;

str1的retain count是個(gè)很大的數(shù)字。Objective-C對常量字符串做了特殊處理。

當(dāng)然,如果你這樣創(chuàng)建NSString,得到的retain count依然為1

NSString *str2 = [NSString stringWithFormat:@”123”];

涉及的示例程序代碼(已去除隱藏,覺得有用的話請頂一下此文):http://files.cnblogs.com/VinceYuan/objective-c-memman.zip

1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,720評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,690評論 2 370

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