天天看點

Autorelease的疑問

先看一下下面兩段代碼分别輸出結果是什麼:

1  ARC 環境下: 

NSObject *obj = [[NSObject alloc] init];
id __autoreleasing o = obj;
NSLog(@"ARC:%d", _objc_rootRetainCount(obj)); 
           

2  MRC環境下:

NSObject *obj = [[NSObject alloc] init];
[obj  autorelease];
NSLog(@"MRC:%d", obj .retainCount); 
           

結果:

ARC:2

MRC:1

這裡産生幾個疑問:

1 Autoreleasepool裡的對象不是用數組存的麼?

2 為什麼add到Autoreleasepool的對象引用計數沒有發生變化?

3 ARC下為什麼是2,而MRC下是1?

針對前兩個問題, 查了一下資料《Pro.Multithreading.and.Memory.Management.for.iOS.and.OS.X》:

當你在mrc下調用 [obj  autorelease];時,NSObject的autorelease方法的GNUstep實作是這樣的:

- (id) autorelease {
     [NSAutoreleasePool addObject:self]; 
}

- (void) addObject: (id)anObj {
     [array addObject:anObj]; 
}
           

當然具體實作也是有優化的。

Apple的實作是這樣的:

在AutoreleasePoolPage這個類裡,

(可以看這裡—》http://opensource.apple.com/source/objc4/objc4-493.11/runtime/objc-arr.mm)

static inline id autorelease(id obj) {
     /* It corresponds to NSAutoreleasePool class method addObject. */
     AutoreleasePoolPage *autoreleasePoolPage = /* getting active AutoreleasePoolPage object */
     autoreleasePoolPage->add(obj); 
}

           
id* add(id obj) {
     assert(!full());
     unprotect();
     *next++ = obj;
     protect();
     return next-1;
 }
           

        我們可以看到實際上隻是做了一個add操作,GNUstep addObject裡的array實際上使用link list去實作的,而apple用的是一個動态數組,從上面的add方法的實作可以看出隻有指針操作, 是以不會對引用計數造成影響。

         第3個問題在arc下引用計數發生變化 是這一句id __autoreleasing o = obj;導緻的。

這個可以參見這裡:http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.semantics

其中有這樣的描述:

“For __autoreleasing objects, the new pointer is retained, autoreleased, and stored into the lvalue using primitive semantics.”

也就是說上面的代碼在arc下,編譯器做轉化的時候實際上會轉化為:

id o = [obj retain] autorelease];

是以引用計數就變成2了。