成人午夜激情影院,小视频免费在线观看,国产精品夜夜嗨,欧美日韩精品一区二区在线播放

Objective-C內(nèi)存管理總結(jié)(全)

2011-02-24 17:40:10來源:cocoachina作者:

iPhone系統(tǒng)中的Objective-C的內(nèi)存管理機(jī)制是比較靈活的,即可以拿來像C/C++一樣用,也可以加個AutoreleasePool讓它升級為半自動化的內(nèi)存管理語言。當(dāng)然,也不能拿JAVA虛擬機(jī)中的全自動化GC來比〜

iPhone系統(tǒng)中的Objective-C的內(nèi)存管理機(jī)制是比較靈活的,即可以拿來像C/C++一樣用,也可以加個AutoreleasePool讓它升級為半自動化的內(nèi)存管理語言。當(dāng)然,也不能拿JAVA虛擬機(jī)中的全自動化GC來比〜

一,引用計(jì)數(shù)是實(shí)例對象的內(nèi)存回收唯一參考

引用計(jì)數(shù)(retainCount)是Objective-C管理對象引用的唯一依據(jù)。調(diào)用實(shí)例的release方法后,此屬性減一,減到為零時對象的dealloc方法被自動調(diào)用,進(jìn)行內(nèi)存回收操作,也就是說我們永不該手動調(diào)用對象的dealloc方法。

它的內(nèi)存管理API老簡單老簡單了,下面就是它主要操作接口:

1,alloc, allocWithZone,new(帶初始化)
   為對象分配內(nèi)存,retainCount為“1”,并返回此實(shí)例

2,release
   retainCount 減“1”,減到“0”時調(diào)用此對象的dealloc方法

3,retain
   retainCount 加“1”

4,copy,mutableCopy
   復(fù)制一個實(shí)例,retainCount數(shù)為“1”,返回此實(shí)例。所得到的對象是與其它上下文無關(guān)的,獨(dú)立的對象(干凈對象)。

5,autorelease
   在當(dāng)前上下文的AutoreleasePool棧頂?shù)腶utoreleasePool實(shí)例添加此對象,由于它的引入使Objective-C(非GC管理環(huán)境)由全手動內(nèi)存管理上升到半自動化。


二,Objective-C內(nèi)存管理準(zhǔn)則

我們可以把上面的接口按對retainCount的操作性質(zhì)歸為兩類,
A類是加一操作:1,3,4
B類是減一操作:2,5(延時釋放)

內(nèi)存管理準(zhǔn)則如下:
1,A與B類的調(diào)用次數(shù)保持一制
2,為了很好的保障準(zhǔn)則一,以實(shí)例對象為單位,誰A了就誰B,沒有第二者參與

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSObject *o = [[NSObject alloc] init];    //retainCount為1
[o retain];    //retainCount為2
[o release]; //retainCount為1
[o autorelease]; //retainCount為1
[pool release]; //retaincount為0,觸發(fā)dealloc方法

三,對象的擁有者

面向?qū)ο箢I(lǐng)域里有個引用的概念,區(qū)別于繼承,引用常被用來當(dāng)做偶合性更小的設(shè)計(jì)。繼承是強(qiáng)依賴,對吧。我們要降偶軟件的設(shè)計(jì),就要盡量減少對它的使用。但沒有任何偶合的模塊或功能是沒有用的〜對吧,那我們只能多用引用了吧。一個實(shí)例擁有另一個實(shí)例的時候,我們稱它為引用了另一個實(shí)例。

比如ClassA類的一個屬性對象的Setter方法:

- (void)setMyArray:(NSMutableArray *)newArray {
    if (myArray != newArray) {
        [myArray release];
        myArray = [newArray retain];
    }
}

假設(shè)這個類的一個實(shí)例為'a',調(diào)用setMyArray后,我們就可以說a擁有了一個新的myArray實(shí)例,也可以說a引用了一個新的myArray實(shí)例。其中調(diào)用的retain方法,使myArray的retainCount加一,我們需要注意以下兩個地方:
1,setMyarray方法中,在retain之前先release了舊實(shí)例一次
2,在本實(shí)例的dealloc方法中,本應(yīng)該是要再次release當(dāng)前實(shí)例的,但回頭看看參考內(nèi)存管理準(zhǔn)則。它并不合理,對吧。。。多了一次release。這里比較推薦的做法是:
[myArray setMyArray:nil];
這樣可以巧妙的使當(dāng)前實(shí)例release而不出錯(我們可以向nil發(fā)送消息〜其實(shí)它本身就是個整數(shù)0),并符合我們的內(nèi)存管理準(zhǔn)則。更主要的是,很簡單,你不需要考慮過多的事情。

另外一個比較容易忽略而又比較經(jīng)典的問題是實(shí)例變量的循環(huán)引用,Objective-C為此區(qū)分了,其實(shí)也相當(dāng)相當(dāng)?shù)暮唵危?br /> 1,強(qiáng)引用,上面講的就是強(qiáng)引用,存在retainCount加一。
2,弱引用,但凡是assign聲明并直接用指針賦值實(shí)現(xiàn)的被稱之為弱引用,不存在retainCount加一的情況。

四,AutoreleasePool使Objective-C成為內(nèi)存管理半自動化語言

如果僅僅是上面這些,很簡單,對吧。但往往很多人都會迷糊在自動內(nèi)存管理這塊上,感覺像是有魔法,但其實(shí)原理也很簡單〜

先看看最經(jīng)典的程序入口程序:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];

我們先把pool看成一個普通對象〜很簡單,先是alloc,pool的retainCount為1。第三句release,retainCount為0,自動調(diào)用它的dealloc方法。它和任何其它普通對象沒 任何區(qū)別。

魔法在哪里?
在聲明pool后,release它之前的這段代碼,所有段里的代碼(先假設(shè)中間沒有聲明其它的AutoreleasePool實(shí)例),凡是調(diào)用了autorelase方法的實(shí)例,都會把它的retainCount加1,并在此pool實(shí)例中添1次此實(shí)例要回收的記錄以做備案。當(dāng)此pool實(shí)例dealloc時,首先會檢查之前備案的所有實(shí)例,所有記錄在案的實(shí)例都會依次調(diào)用它的release方法。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSObject *o = [[NSObject alloc] init];
[o autorelease];                                //在pool實(shí)例dealloc時,release一次此實(shí)例,重要的是并不是在此行去release
NSLog(@"o retainCount:%d",[o retainCount]);    //此時還可以看到我們的o實(shí)例還是可用的,并且retainCount為1
[pool release];    //pool 的 retainCount為0,自動調(diào)用其dealloc方法,我們之前備案的小o也將在這里release一次(因?yàn)樵蹅冎皟H僅autorelease一次)

真對同一個實(shí)例,同一個Pool是可以多次注冊備案(autorelease)的。在一些很少的情況化可能會出現(xiàn)這種需求:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSObject *o = [[NSObject alloc] init];
[o retain];
[o autorelease];
[o autorelease];
[pool release];

我們調(diào)用了兩次A類(retainCount加1的方法),使其retainCount為2,而接下來的兩次autorelease方法調(diào)用,使其在pool中注冊備案了兩次。這里的pool將會在回收時調(diào)用此實(shí)例的兩次release方法。使其retainCount降為0,完成回收內(nèi)存的操作,其實(shí)這也是完全按照內(nèi)存管理規(guī)則辦事的好處〜

AutoreleasePool是被嵌套的!
池是被嵌套的,嵌套的結(jié)果是個棧,同一線程只有當(dāng)前棧頂pool實(shí)例是可用的:

|  pool_3  |
|  ---------      |
|  pool_2      |
|  ---------   |
|  pool_1  |
|_______|

其代碼如下:

NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init];
NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
NSAutoreleasePool *pool3 = [[NSAutoreleasePool alloc] init];

NSObject *o = [[NSObject alloc] init] autorelease];

[pool3 release];
[pool2 release];
[pool1 release];

我們可以看到其棧頂是pool3,o的autorelease是把當(dāng)前的release放在棧頂?shù)膒ool實(shí)例管理。。。也就是pool3。
在生命周期短,產(chǎn)生大量放在autoreleasePool中管理實(shí)例的情況下經(jīng)常用此方法減少內(nèi)存使用,達(dá)到內(nèi)存及時回收的目的。

AutoreleasePool還被用在哪里?
在上面的例子里,也可以看到,我們在執(zhí)行autorelease方法時,并沒有時時的進(jìn)行release操作〜它的release被延時到pool實(shí)例的dealloc方法里。這個小細(xì)節(jié)使我們的Objective-C用起來可以在方法棧中申請堆中的內(nèi)存,創(chuàng)建實(shí)例,并把它放在當(dāng)前pool中延遲到此方法的調(diào)用者釋放〜


以上就是我想到的內(nèi)存管理總結(jié)〜〜〜〜也就這么多吧〜日常工作用夠用了〜不夠的,沒想到的大家補(bǔ)充〜
 

贊助商鏈接:

主站蜘蛛池模板: 黎城县| 嘉峪关市| 黔江区| 临潭县| 邹城市| 江津市| 中阳县| 固镇县| 吉林省| 韶关市| 南靖县| 太仓市| 章丘市| 临猗县| 安宁市| 唐河县| 甘孜县| 黎平县| 苍南县| 沁阳市| 铁岭县| 莒南县| 乐都县| 钟山县| 乐都县| 佛山市| 揭阳市| 蒙阴县| 阿坝| 独山县| 兴安县| 新沂市| 南开区| 衡阳市| 双辽市| 信丰县| 泾川县| 呼伦贝尔市| 新竹县| 南靖县| 横峰县|