內(nèi)存分配
在iOS中,數(shù)據(jù)是存儲(chǔ)在堆和棧上的,堆上的內(nèi)存需要管理,棧上的內(nèi)存并不需要。
-
非OC對(duì)象(基礎(chǔ)數(shù)據(jù)類(lèi)型)存儲(chǔ)在棧上
??int,double,float,NSInteger,CGFloat,BOOL等
-
OC對(duì)象存儲(chǔ)在堆上
?? NSString,NSArray,NSDictionary等
引用計(jì)數(shù)
-
MRC引用計(jì)數(shù)
對(duì)象操作的四個(gè)類(lèi)別
| 對(duì)象操作 | OC中對(duì)應(yīng)的方法 | 對(duì)應(yīng)的 retainCount 變化 |
|---|---|---|
| 生成并持有對(duì)象 | alloc/new/copy/mutableCopy等 | +1 |
| 持有對(duì)象 | retain | +1 |
| 釋放對(duì)象 | release | -1 |
| 廢棄對(duì)象 | dealloc | - |
四個(gè)法則
- 自己生成的對(duì)象,自己持有。
- 非自己生成的對(duì)象,自己也能持有。
- 不在需要自己持有對(duì)象的時(shí)候,釋放。
- 非自己持有的對(duì)象無(wú)需釋放。
如下是四個(gè)黃金法則對(duì)應(yīng)的代碼示例:
/*
* 自己生成并持有該對(duì)象
*/
id obj0 = [[NSObeject alloc] init];
id obj1 = [NSObeject new];
/*
* 不在需要自己持有的對(duì)象的時(shí)候,釋放
*/
id obj = [[NSObeject alloc] init]; // 此時(shí)持有對(duì)象
[obj release]; // 釋放對(duì)象
/*
* 指向?qū)ο蟮闹羔樔跃捅槐A粼趏bj這個(gè)變量中
* 但對(duì)象已經(jīng)釋放,不可訪問(wèn)
*/
/*
* 非自己持有的對(duì)象無(wú)法釋放
*/
id obj = [NSArray array]; // 非自己生成的對(duì)象,且該對(duì)象存在,但自己不持有
[obj release]; // 此時(shí)將運(yùn)行時(shí)crash 或編譯器報(bào)error。 非ARC下,調(diào)用該方法會(huì)導(dǎo)致編譯器報(bào) issues。此操作的行為是未定義的,可能會(huì)導(dǎo)致運(yùn)行時(shí) crash 或者其它未知行為
其中 非自己生成的對(duì)象,且該對(duì)象存在,但自己不持有 這個(gè)特性是使用autorelease來(lái)實(shí)現(xiàn)的,示例代碼如下:
- (id) getAObjNotRetain {
id obj = [[NSObject alloc] init]; // 自己持有對(duì)象
[obj autorelease]; // 取得的對(duì)象存在,但自己不持有該對(duì)象
return obj;
}
autorelease 使得對(duì)象在超出生命周期后能正確的被釋放(通過(guò)調(diào)用release方法)。在調(diào)用release 后,對(duì)象會(huì)被立即釋放,而調(diào)用autorelease 后,對(duì)象不會(huì)被立即釋放,而是注冊(cè)到 autoreleasepool 中,經(jīng)過(guò)一段時(shí)間后 pool結(jié)束,此時(shí)調(diào)用release方法,對(duì)象被釋放。
在MRC的內(nèi)存管理模式下,與對(duì)變量的管理相關(guān)的方法有:retain, release 和 autorelease。retain 和 release 方法操作的是引用記數(shù),當(dāng)引用記數(shù)為零時(shí),便自動(dòng)釋放內(nèi)存。并且可以用 NSAutoreleasePool 對(duì)象,對(duì)加入自動(dòng)釋放池(autorelease 調(diào)用)的變量進(jìn)行管理,當(dāng) drain 時(shí)回收內(nèi)存。
-
ARC引用計(jì)數(shù)
ARC 是蘋(píng)果引入的一種自動(dòng)內(nèi)存管理機(jī)制,會(huì)根據(jù)引用計(jì)數(shù)自動(dòng)監(jiān)視對(duì)象的生存周期,實(shí)現(xiàn)方式是在編譯時(shí)期自動(dòng)在已有代碼中插入合適的內(nèi)存管理代碼以及在 Runtime 做一些優(yōu)化。ARC其實(shí)也是基于引用計(jì)數(shù),只是編譯器在編譯時(shí)期自動(dòng)在已有代碼中插入合適的內(nèi)存管理代碼(包括 retain、release、copy、autorelease、autoreleasepool)以及在 Runtime 做一些優(yōu)化。
現(xiàn)在的iOS開(kāi)發(fā)基本都是基于ARC的,所以開(kāi)發(fā)人員大部分情況都是不需要考慮內(nèi)存管理的,因?yàn)榫幾g器已經(jīng)幫你做了。為什么說(shuō)是大部分呢,因?yàn)榈讓拥?Core Foundation 對(duì)象由于不在 ARC 的管理下,所以需要自己維護(hù)這些對(duì)象的引用計(jì)數(shù)。
還有就算循環(huán)引起情況就算由于互相之間強(qiáng)引用,引用計(jì)數(shù)永遠(yuǎn)不會(huì)減到0,所以需要自己主動(dòng)斷開(kāi)循環(huán)引用,使引用計(jì)數(shù)能夠減少。