首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

AutoreleasePool从入门到放弃(6)

AutoreleasePool从入门到放弃(6)

pop(void *token)

    static inline void pop(void *token)
        {
            AutoreleasePoolPage *page;
            id *stop;
     
            if (token == (void*)EMPTY_POOL_PLACEHOLDER) {
                // Popping the top-level placeholder pool.
                if (hotPage()) {
                    // Pool was used. Pop its contents normally.
                    // Pool pages remain allocated for re-use as usual.
                    pop(coldPage()->begin());
                } else {
                    // Pool was never used. Clear the placeholder.
                    setHotPage(nil);
                }
                return;
            }
     
            page = pageForPointer(token);
            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 (PrintPoolHiwat) printHiwat();
     
            page->releaseUntil(stop);
     
            // memory: delete empty children
            if (DebugPoolAllocation  &&  page->empty()) {
                // special case: delete everything during page-per-pool debugging
                AutoreleasePoolPage *parent = page->parent;
                page->kill();
                setHotPage(parent);
            } else if (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();
                }
            }
        }

    如果传入token为EMPTY_POOL_PLACEHOLDER并且当前存在AutoreleasePoolPage就从最顶层父AutoreleasePoolPage的begin位开始pop;如果当前不存在AutoreleasePoolPage则表明未使用AutoreleasePool,所以重置当前AutoreleasePoolPage并且直接return

    如果传入的非EMPTY_POOL_PLACEHOLDER,则通过函数pageForPointer来查找具体在哪个AutoreleasePoolPage中。
        如果stop不为POOL_BOUNDARY
            stop为起始位并且无父AutoreleasePoolPage
            处理新老SDK的兼容问题

    从当前AutoreleasePoolPage向前release对象,直到stop

    Debug模式并且当前AutoreleasePoolPage为空
        删除所有子AutoreleasePoolPage
        重新配置当前AutoreleasePoolPage

    pop所有对象时
        删除所有子AutoreleasePoolPage
        重新配置当前AutoreleasePoolPage

    如果存在子AutoreleasePoolPage
        如果stop所在AutoreleasePoolPage存储对象少于一半则删除子AutoreleasePoolPage的子AutoreleasePoolPage
        否则删除....(好绕口,这里应该是根据当前存储情况删除未使用到的空AutoreleasePoolPage)

由转换的c++代码我们可以看出objc_autoreleasePoolPop的参数即objc_autoreleasePoolPush生成的变量,所以@autoreleasePool block在出了其作用域时都会将自身包裹的autoreleased对象进行出栈操作

objc_autoreleasePoolPush()
objc_autoreleasePoolPop(atautoreleasepoolobj)
两个函数我们都基本分析完了,现在我们看看在这个两个函数之间的对象调用autorelease的流程

    - (id)autorelease {
        return ((id)self)->rootAutorelease();
    }

    inline id objc_object::rootAutorelease()
    {
        if (isTaggedPointer()) return (id)this;
        if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;
     
        return rootAutorelease2();
    }

这里我们看到TaggedPointer是直接返回的,也验证了之前所说的NSString问题。
prepareOptimizedReturn属于TLS优化部分我们先放放

        static inline id autorelease(id obj)
        {
            assert(obj);
            assert(!obj->isTaggedPointer());
            id *dest __unused = autoreleaseFast(obj);
            assert(!dest  ||  dest == EMPTY_POOL_PLACEHOLDER  ||  *dest == obj);
            return obj;
        }

我们看到autorelease方法其实也是调用之前的autoreleaseFast函数进行对象入栈操作的
返回列表