1. ARC的基本概念
在objc中采用automatic reference counting 機(jī)制, 讓編譯器來進(jìn)行內(nèi)存管理。在降低程序崩潰,內(nèi)存管理泄漏等風(fēng)險(xiǎn)的同時(shí),很大程度減少了程序員的工作量。
-------摘自蘋果發(fā)開者文檔自動(dòng)引用計(jì)數(shù)的思維方式:
自己生成的對(duì)象,自己持有。
非自己生成的對(duì)象,自己也能持有。
再需要自己持有對(duì)象時(shí)釋放。
非自己持有的對(duì)象無法釋放。
對(duì)象操作與OBJC方法的對(duì)應(yīng)。
生成并持有對(duì)象 ------
alloc/new/copy/mutableCopy(這些方法意味著自己生成的對(duì)象只能自己持有)持有對(duì)象 ------
retain釋放對(duì)象 ------
release銷毀對(duì)象 ------
dealoc非自己生成的對(duì)象,自己也能持有
/*取得的對(duì)象存在,但自己不持有對(duì)象*/
id obj = [NSMutableArray array]//取得非自己生成的對(duì)象
[obj retain]//自己持有對(duì)象
- 對(duì)幾種內(nèi)存情況的總結(jié)
-
alloc/new/copy/mutableCopy這些方法自己生成且持有。
-
- 如果是
array等方法生成的對(duì)象不是自己持有的,但是可以通過調(diào)用retain方法變成自己持有。 如果對(duì)自己生成且持有的對(duì)象使用```autorelease```方法,可以是對(duì)象存在但自己不持有。如:
id obj = [[obj alloc] init];
[obj autorealease];
/*取得對(duì)象存在,但自己不持有*/
- objc中,```array```等生成對(duì)象但自己不持有的方法內(nèi)部是通過```autorealease```方法實(shí)現(xiàn)的。
2.alloc/retain/release/dealloc方法的實(shí)現(xiàn)
-
alloc方法的內(nèi)部實(shí)現(xiàn):
alloc方法內(nèi)部調(diào)用的是allocWithZone:(NSDefaultZone())這個(gè)對(duì)象方法。該方法又調(diào)用了NSAllocateObject()函數(shù)。所以在這里只需關(guān)注該方法即可。
該方法內(nèi)部如下:
struct obj_layout
{
NSInteger retained;
};
inline id
NSAllocateObject(Class aClass,NSInteger extraBytes,NSZone *zone){
int size = 計(jì)算容納對(duì)象所需內(nèi)存大小;
id new = NSZoneMalloc(zone,size);
memset (new,0,size);
new = (id) & ((struct obj_layout *) new)[1];
}
- 該函數(shù)將該內(nèi)存空間置為0(包括
obj_layout這個(gè)結(jié)構(gòu)體),且返回一個(gè)作為對(duì)象而使用的指針。
該內(nèi)存空間內(nèi)部,也就是對(duì)象所處的內(nèi)存空間內(nèi)部,頭部是struct obj_layout這個(gè)結(jié)構(gòu)體,接下來才是對(duì)象。alloc方法返回的指針指向的頭部以下的內(nèi)容。也就是除去結(jié)構(gòu)體的內(nèi)容。
可以通過查看retainCount這個(gè)方法的源代碼驗(yàn)證以上結(jié)論:
- (NSUInteger)retainCout{
return NSExtraRefcount(self)+1;//需要注意此處的+1,對(duì)象內(nèi)存的頭部結(jié)構(gòu)體里的retain其實(shí)為0,所以+1。
}
inline NSUInteger
NSExtraRefcount(id anObject){
return((struct obj_layout *) anObject)[-1].retained;//此處需要注意-1,因?yàn)橐L問的實(shí)質(zhì)對(duì)象所處內(nèi)存空間的頭部,也就是結(jié)構(gòu)體obj_layout.
}
3.retain,release即delloc方法的實(shí)現(xiàn)。
無論是retain還是release,其實(shí)內(nèi)部都是通過操作對(duì)象所處內(nèi)存空間頭部的結(jié)構(gòu)體來實(shí)現(xiàn)的。
-
retain:
((struct obj_layout *) anObject)[-1].retained++;
-
release:這個(gè)方法的內(nèi)部實(shí)現(xiàn)稍微要比retain復(fù)雜一點(diǎn),是因?yàn)橐袛嘁糜?jì)數(shù)是否為0,如果為0 則需要銷毀對(duì)象(即調(diào)用dealloc方法)
- (void)release{
if(NSDecrementExtraRefCountWasZero(self)){
[self dealloc];
}
}
BOOL
NSDecrementExtraRefCountWasZero(id anObject){
if (obj_layout結(jié)構(gòu)體內(nèi)部的retained是否為0)
{
若為0,返回yes
}else{
返回no
}
}
-
delloc方法:調(diào)用NSDellocatteObject()函數(shù),其內(nèi)部free掉struct objc_layout結(jié)構(gòu)體。
以上即是alloc,release,retain,delloc方法在GNUstep的實(shí)現(xiàn),*總結(jié)如下:
1.在Objective-C的對(duì)象中存在引用計(jì)數(shù)這一數(shù)值;
2.調(diào)用alloc,retain方法后,引用計(jì)數(shù)+1;
3.引用計(jì)數(shù)為0時(shí),調(diào)用delloc方法銷毀對(duì)象。