autoreleasepool 學(xué)習(xí)筆記

前言

關(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ì)用一個(gè)棧上的c++對象來替換@autoreleasepool{};并在對象的構(gòu)造中調(diào)用了:objc_autoreleasePoolPush();在析構(gòu)中調(diào)用了:objc_autoreleasePoolPop(atautoreleasepoolobj)。

其實(shí)際都是調(diào)用runtime中c++類AutoreleasePoolPagepushpop方法。

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;
}

各個(gè)變量基本上都能見其名知其意。

  • autorelease類型的對象都是通過AutoreleasePoolPage管理的。
  • masOS中每個(gè)page的大小是4096個(gè)字節(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)算newdelete,而SIZEmacOS下定義為4096。

  • 內(nèi)存從低址值存依次放著各個(gè)成員變量(56個(gè)字節(jié));然后存放POOL_BOUNDARYautorelease類型對象的指針。
  • 其中next是指向下一個(gè)autorelease類型對象的指針該存放的位置。
  • 每個(gè)AutoreleasePoolPage對象通過parentchild來連接(雙鏈表)。
  • autoreleasepool中嵌套autoreleasepool實(shí)際上是在pagepush一個(gè)POOL_BOUNDARY(nil)。

當(dāng)調(diào)用對象的autorelease方法時(shí),該對象的指針會被存放到page中,而當(dāng)page進(jìn)行pop操作時(shí),會根據(jù)傳入的POOL_BOUNDARY(nil)指針的地址來釋放大于此地址的page中的對象。

結(jié)尾

紙上得來終覺淺,絕知此事要躬行。

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

相關(guān)閱讀更多精彩內(nèi)容

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