對(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)