autorelease原理

對(duì)象調(diào)用autorelease會(huì)在它所在的@autoreleasepool{}大括號(hào)結(jié)束的時(shí)候調(diào)用release釋放,

MRC下
 NSLog(@"11111");
    @autoreleasepool {
        CXWork *work = [[[CXWork alloc]init] autorelease];
        //        CXWork *work = [[CXWork alloc]init];
    }
    NSLog(@"22222");

進(jìn)一步研究

用xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
將main.m轉(zhuǎn)成main.cpp觀察
    @autoreleasepool {
       CXWork *work = [[[CXWork alloc]init] autorelease];
    }
如下
{
 __AtAutoreleasePool __autoreleasepool;//調(diào)用構(gòu)造函數(shù)
 CXWork *work = ((CXWork *(*)(id, SEL))(void *)objc_msgSend)((id)((CXWork *(*)(id, SEL))(void *)objc_msgSend)((id)((CXWork *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("CXWork"), sel_registerName("alloc")), sel_registerName("init")), sel_registerName("autorelease"));
    // 結(jié)構(gòu)體銷毀,調(diào)用結(jié)構(gòu)體的析構(gòu)函數(shù)
 }

 struct __AtAutoreleasePool {
 __AtAutoreleasePool() { // 構(gòu)造函數(shù) 在生成結(jié)構(gòu)體變量的時(shí)候調(diào)用
 atautoreleasepoolobj = objc_autoreleasePoolPush();
 
 }
 ~__AtAutoreleasePool() {//析構(gòu)函數(shù),在結(jié)構(gòu)體銷毀的時(shí)候調(diào)用
 objc_autoreleasePoolPop(atautoreleasepoolobj);
 
 }
 void * atautoreleasepoolobj;
 };
 
void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}

void
objc_autoreleasePoolPop(void *ctxt)
{
    AutoreleasePoolPage::pop(ctxt);
}

自動(dòng)釋放池的主要底層數(shù)據(jù)結(jié)構(gòu)是:__AtAutoreleasePool、AutoreleasePoolPage,調(diào)用了autorelease的對(duì)象最終都是通過AutoreleasePoolPage對(duì)象來管理的,每個(gè)AutoreleasePoolPage對(duì)象占用4096字節(jié)內(nèi)存,除了用來存放它內(nèi)部的成員變量,剩下的空間用來存放autorelease對(duì)象的地址,當(dāng)一個(gè)AutoreleasePoolPage不夠用時(shí),就會(huì)創(chuàng)建多個(gè),所有的AutoreleasePoolPage對(duì)象通過雙向鏈表的形式連接在一起.

AutoreleasePoolPage精簡(jiǎn)版
class AutoreleasePoolPage {
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage *const parent;
AutoreleasePoolPage * child;
unit32_t const depth;
unit32_t hiwat;
}

objc_autoreleasePoolPush()怎么把a(bǔ)utorelease對(duì)象地址放進(jìn)AutoreleasePoolPage?
調(diào)用push方法會(huì)將一個(gè)POOL_BOUNDARY入棧,并且返回其存放的內(nèi)存地址
調(diào)用pop方法時(shí)傳入一個(gè)POOL_BOUNDARY的內(nèi)存地址,會(huì)從最后一個(gè)入棧的對(duì)象開始發(fā)送release消息,直到遇到這個(gè)POOL_BOUNDARY.(先進(jìn)后出的效果).多個(gè)autoreleasePool嵌套相當(dāng)于產(chǎn)生多個(gè)POOL_BOUNDARY來區(qū)分每個(gè)autoreleasePool的作用域存放的對(duì)象.
id *next指向了下一個(gè)能存放autorelease對(duì)象地址的區(qū)域

iOS在主線程的Runloop中注冊(cè)了2個(gè)Observer

第1個(gè)Observer監(jiān)聽了kCFRunLoopEntry事件,會(huì)調(diào)用objc_autoreleasePoolPush()
第2個(gè)Observer監(jiān)聽了kCFRunLoopBeforeWaiting事件,會(huì)調(diào)用objc_autoreleasePoolPop()、objc_autoreleasePoolPush(),監(jiān)聽了kCFRunLoopBeforeExit事件,會(huì)調(diào)用objc_autoreleasePoolPop() 使得pop和push對(duì)應(yīng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容