前言
關(guān)于AutoreleasePool的實(shí)現(xiàn)原理导盅,有很多很多優(yōu)秀的博客(都是大神們無私的奉獻(xiàn))僻澎,他們都對其進(jìn)行了詳細(xì)的介紹扁誓,我也是看這些文章配合runtime
源碼進(jìn)行學(xué)習(xí)的。文章只是做了一些干練的總結(jié)脱盲,方便自己或者他人復(fù)習(xí),具體的細(xì)節(jié)以及分析就不寫了(大神們寫得太好了)日缨,想要學(xué)習(xí)的移步大神們的博客钱反。(ps: 雖然這些博客中的runtime部分源碼已經(jīng)修改,但是其基本邏輯還是沒有變動的匣距,runtime可調(diào)式工程在此下載)
大神的文章
黑幕背后的Autorelease - sunnyxx大神
Objective-C Autorelease Pool 的實(shí)現(xiàn)原理 - 雷純鋒的技術(shù)博客
@autoreleasepool的實(shí)質(zhì)
通過clang -rewrite-objc
指令可以將:
int main (int argc, char * argv[]) {
@autoreleasepool {
}
}
轉(zhuǎn)換成:
extern "C" __declspec(dllimport) void * objc_autoreleasePoolPush(void);
extern "C" __declspec(dllimport) void objc_autoreleasePoolPop(void *);
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)
int main (int argc, char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
}
}
可以看到編譯器實(shí)質(zhì)用一個棧上的c++對象來替換@autoreleasepool{}
面哥;并在對象的構(gòu)造中調(diào)用了:objc_autoreleasePoolPush()
;在析構(gòu)中調(diào)用了:objc_autoreleasePoolPop(atautoreleasepoolobj)
毅待。
其實(shí)際都是調(diào)用runtime
中c++類AutoreleasePoolPage
的push
和pop
方法尚卫。
AutoreleasePoolPage的定義
看一下AutoreleasePoolPage
中定義的成員變量:
class AutoreleasePoolPage
{
magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
}
各個變量基本上都能見其名知其意。
-
autorelease
類型的對象都是通過AutoreleasePoolPage
管理的尸红。 - 在
masOS
中每個page的大小是4096個字節(jié)吱涉。
對于page的大小,可以從源碼中看到:
static void * operator new(size_t size) {
return malloc_zone_memalign(malloc_default_zone(), SIZE, SIZE);
}
static void operator delete(void * p) {
return free(p);
}
其重寫了運(yùn)算new
和delete
外里,而SIZE
在macOS
下定義為4096怎爵。
- 內(nèi)存從低址值存依次放著各個成員變量(56個字節(jié));然后存放
POOL_BOUNDARY
和autorelease
類型對象的指針盅蝗。 - 其中
next
是指向下一個autorelease
類型對象的指針該存放的位置鳖链。 - 每個
AutoreleasePoolPage
對象通過parent
和child
來連接(雙鏈表)。 - 在
autoreleasepool
中嵌套autoreleasepool
實(shí)際上是在page
中push
一個POOL_BOUNDARY(nil)
风科。
當(dāng)調(diào)用對象的autorelease
方法時撒轮,該對象的指針會被存放到page
中乞旦,而當(dāng)page
進(jìn)行pop
操作時,會根據(jù)傳入的POOL_BOUNDARY(nil)
指針的地址來釋放大于此地址的page
中的對象题山。
結(jié)尾
紙上得來終覺淺兰粉,絕知此事要躬行。