AutoreleasePool源码学习

 

自动释放池压栈方法:

    static inline void *push() 
    {
        id *dest;
        if (slowpath(DebugPoolAllocation)) {//debug环境下走
            dest = autoreleaseNewPage(POOL_BOUNDARY);
        } else {
            dest = autoreleaseFast(POOL_BOUNDARY);//压入哨兵对象
        }
        ASSERT(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
        return dest;
    }

 

正常情况下会走autoreleaseFast(POOL_BOUNDARY),压入哨兵对象

    static inline id *autoreleaseFast(id obj)
    {
        AutoreleasePoolPage *page = hotPage();//获取当前页表
        if (page && !page->full()) {//如果当前页表存在且不满
            return page->add(obj);//直接加入
        } else if (page) {//pageFull处理
            return autoreleaseFullPage(obj, page);
        } else {//无page处理
            return autoreleaseNoPage(obj);
        }
    }

当前hotPage页满时调用FullPage方法:

    static __attribute__((noinline))
    id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page)
    {
        // The hot page is full. 
        // Step to the next non-full page, adding a new page if necessary.
        // Then add the object to that page.
        ASSERT(page == hotPage());//断言,判断当前page是否为焦点页(hot)
        ASSERT(page->full()  ||  DebugPoolAllocation);

        do {//顺着子节点找到最新的页面,并在最新孩子下方创建新的页
            if (page->child) page = page->child;
            else page = new AutoreleasePoolPage(page);
        } while (page->full());
        
        setHotPage(page);//设置当前新页为hot
        return page->add(obj);//将对象加入页栈中
    }

添加对象obj到page中

    id *add(id obj)
    {
        ASSERT(!full());
        unprotect();//解锁
        id *ret = next;  // faster than `return next-1` because of aliasing
        *next++ = obj;//next指针存放然后++ 指针平移
        protect();//上锁
        return ret;
    }

 

自动释放池出栈方法:

    static inline void
    pop(void *token)
    {
        AutoreleasePoolPage *page;
        id *stop;
        //如果当前为占位符(哨兵),则直接清空页就行了
        if (token == (void*)EMPTY_POOL_PLACEHOLDER) {
            // Popping the top-level placeholder pool.
            page = hotPage();
            if (!page) {
                // Pool was never used. Clear the placeholder.
                return setHotPage(nil);
            }
            // Pool was used. Pop its contents normally.
            // Pool pages remain allocated for re-use as usual.
            page = coldPage();
            token = page->begin();
        } else {
            page = pageForPointer(token);
        }
        //stop就是栈顶指针,指向end(),就会依次释放直到遇见哨兵
        stop = (id *)token;
        if (*stop != POOL_BOUNDARY) {
            if (stop == page->begin()  &&  !page->parent) {
                // Start of coldest page may correctly not be POOL_BOUNDARY:
                // 1. top-level pool is popped, leaving the cold page in place
                // 2. an object is autoreleased with no pool
            } else {
                // Error. For bincompat purposes this is not 
                // fatal in executables built with old SDKs.
                return badPop(token);
            }
        }

        if (slowpath(PrintPoolHiwat || DebugPoolAllocation || DebugMissingPools)) {
            return popPageDebug(token, page, stop);
        }
//        popPage才是真正的处理
        return popPage<false>(token, page, stop);
    }

 

 

 

    template<bool allowDebug>
    static void
    popPage(void *token, AutoreleasePoolPage *page, id *stop)
    {
        if (allowDebug && PrintPoolHiwat) printHiwat();
//        释放页内对象
        page->releaseUntil(stop);

        // memory: delete empty children
//    释放完毕后清理并回收当前页
if (allowDebug && DebugPoolAllocation && page->empty()) { // special case: delete everything during page-per-pool debugging AutoreleasePoolPage *parent = page->parent; page->kill(); setHotPage(parent); } else if (allowDebug && DebugMissingPools && page->empty() && !page->parent) { // special case: delete everything for pop(top) // when debugging missing autorelease pools page->kill(); setHotPage(nil);
//  处理回收子节点 }
else if (page->child) { // hysteresis: keep one empty child if page is more than half full if (page->lessThanHalfFull()) { page->child->kill(); } else if (page->child->child) { page->child->child->kill(); } } }

 

回收页内存放对象:

    void releaseUntil(id *stop) 
    {
        // Not recursive: we don‘t want to blow out the stack 
        // if a thread accumulates a stupendous amount of garbage
        
        while (this->next != stop) {
            // Restart from hotPage() every time, in case -release 
            // autoreleased more objects
            AutoreleasePoolPage *page = hotPage();

            // fixme I think this `while` can be `if`, but I can‘t prove it
            while (page->empty()) {
                page = page->parent;
                setHotPage(page);
            }
      //回收对象内存
            page->unprotect();//解锁
            id obj = *--page->next;
            memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
            page->protect();//上锁

            if (obj != POOL_BOUNDARY) {
                objc_release(obj);//释放
            }
        }

        setHotPage(this);

 

回收页结构

    void kill() 
    {
        // Not recursive: we don‘t want to blow out the stack 
        // if a thread accumulates a stupendous amount of garbage
        AutoreleasePoolPage *page = this;
        while (page->child) page = page->child;

        AutoreleasePoolPage *deathptr;
        do {
            deathptr = page;
            page = page->parent; //变为父节点,一层一层往上
            if (page) {
                page->unprotect();
                page->child = nil;
                page->protect();
            }
            delete deathptr;
        } while (deathptr != this);
    }

 

AutoreleasePool源码学习

上一篇:一个可以大大提升工作效率的插件以及设置


下一篇:c# gridview checkbox实现单选