AutoreleasePool源码

示例demo

AutoreleasePoolPageData

struct AutoreleasePoolPageData
{
    magic_t const magic;
    __unsafe_unretained id *next;
    pthread_t const thread;
    AutoreleasePoolPage * const parent;
    AutoreleasePoolPage *child;
    uint32_t const depth;
    uint32_t hiwat;

    AutoreleasePoolPageData(__unsafe_unretained id* _next, pthread_t _thread, AutoreleasePoolPage* _parent, uint32_t _depth, uint32_t _hiwat)
        : magic(), next(_next), thread(_thread),
          parent(_parent), child(nil),
          depth(_depth), hiwat(_hiwat)
    {
    }
};

这是一个双向链表,有父节点和子节点,还有深度。
magic类似于isa_t中的magic,用于检查这个节点是否已经被初始化了。
thread保存了当前页所在的线程。
每一个自动释放池都是由若干page组成,每个page的大小都是4096字节。

objc_autoreleasePoolPush

static inline void *push() 
    {
        id *dest;
        if (slowpath(DebugPoolAllocation)) {
            // Each autorelease pool starts on a new pool page.
            dest = autoreleaseNewPage(POOL_BOUNDARY);
        } else {
            dest = autoreleaseFast(POOL_BOUNDARY);
        }
        ASSERT(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
        return dest;
    }
/**
方法分三种情况选择不同的代码执行:
有 hotPage 并且当前 page 不满,调用 page->add(obj) 方法将对象添加至 AutoreleasePoolPage 的栈中。
有 hotPage 并且当前 page 已满,调用 autoreleaseFullPage 初始化一个新的页,调用 page->add(obj) 方法将对象添加至 AutoreleasePoolPage 的栈中。
无 hotPage,调用 autoreleaseNoPage 创建一个 hotPage,调用 page->add(obj) 方法将对象添加至 AutoreleasePoolPage 的栈中,最后的都会调用 page->add(obj) 将对象添加到自动释放池中。

hotPage 可以理解为当前正在使用的 AutoreleasePoolPage。
*/
 static inline id *autoreleaseFast(id obj)
    {
        AutoreleasePoolPage *page = hotPage();
        if (page && !page->full()) {
            return page->add(obj);
        } else if (page) {
            return autoreleaseFullPage(obj, page);
        } else {
            return autoreleaseNoPage(obj);
        }
    }
/**
可以看到,加入对象后,next指针增加,类似于栈顶指针。
*/
   id *add(id obj)
    {
        ASSERT(!full());
        unprotect();
        id *ret = next;  // faster than `return next-1` because of aliasing
        *next++ = obj;
        protect();
        return ret;
    }
/**
它会从传入的 page 开始遍历整个双向链表,直到查找到一个未满的 AutoreleasePoolPage
使用构造器传入 parent 创建一个新的 AutoreleasePoolPage
在查找到一个可以使用的 AutoreleasePoolPage 之后,会将该页面标记成 hotPage,然后调动上面分析过的 page->add 方法添加对象。
*/
 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());
        ASSERT(page->full()  ||  DebugPoolAllocation);

        do {
            if (page->child) page = page->child;
            else page = new AutoreleasePoolPage(page);
        } while (page->full());

        setHotPage(page);
        return page->add(obj);
    }
/**
既然当前内存中不存在 AutoreleasePoolPage,就要从头开始构建这个自动释放池的双向链表,也就是说,新的 AutoreleasePoolPage 是没有 parent 指针的。

初始化之后,将当前页标记为 hotPage,然后会先向这个 page 中添加一个 POOL_BOUNDARY 对象,来确保在 pop 调用的时候,不会出现异常。

最后,将 obj 添加到自动释放池中
*/
static __attribute__((noinline))
    id *autoreleaseNoPage(id obj)
    {
        // "No page" could mean no pool has been pushed
        // or an empty placeholder pool has been pushed and has no contents yet
        ASSERT(!hotPage());
        //“No page”可能意味着没有推入池
//或者一个空的占位符池已经被推入并且还没有内容

        bool pushExtraBoundary = false;
        if (haveEmptyPoolPlaceholder()) {
            // We are pushing a second pool over the empty placeholder pool
            // or pushing the first object into the empty placeholder pool.
            // Before doing that, push a pool boundary on behalf of the pool 
            // that is currently represented by the empty placeholder.
            //我们正在将第二个池推到空占位符池上
//或将第一个对象推入空的占位符池。
//在此之前,为池推一个池边界
//当前由空占位符表示。
            pushExtraBoundary = true;
        }
        else if (obj != POOL_BOUNDARY  &&  DebugMissingPools) {
            // We are pushing an object with no pool in place, 
            // and no-pool debugging was requested by environment.
            //我们推一个没有水池的物体,
            //和无池调试是环境要求的。
            _objc_inform("MISSING POOLS: (%p) Object %p of class %s "
                         "autoreleased with no pool in place - "
                         "just leaking - break on "
                         "objc_autoreleaseNoPool() to debug", 
                         objc_thread_self(), (void*)obj, object_getClassName(obj));
            objc_autoreleaseNoPool(obj);
            return nil;
        }
        else if (obj == POOL_BOUNDARY  &&  !DebugPoolAllocation) {
        //我们推的是一个没有水池的水池,
//和未请求每个池分配调试。
//安装并返回空池占位符。
            // We are pushing a pool with no pool in place,
            // and alloc-per-pool debugging was not requested.
            // Install and return the empty pool placeholder.
            return setEmptyPoolPlaceholder();
        }

        // We are pushing an object or a non-placeholder'd pool.

        // Install the first page.
        //我们推入一个对象或一个非占位符池。

//安装第一页。
        AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
        setHotPage(page);
        
        // Push a boundary on behalf of the previously-placeholder'd pool.
        //代表先前占位的池推一个边界。
        if (pushExtraBoundary) {
            page->add(POOL_BOUNDARY);
        }
        //推入被请求的对象或池。
        // Push the requested object or pool.
        return page->add(obj);
    }

原文链接:https://blog.csdn.net/wtl1804/article/details/107764028

objc_autoreleasePoolPop

//pop传入的就是刚刚push了哨兵对象的地址
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 = (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);
        }

        return popPage(token, page, stop);
    }
原文链接:https://blog.csdn.net/wtl1804/article/details/107764028

对象如何加入到自动释放池?

autorelease方法。对象通过调用autorelease方法加入到自动释放池中,而autorelease方法本质是调用了autoreleaseFast方法。

    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;
    }
原文链接:https://blog.csdn.net/wtl1804/article/details/107764028

自动释放池在何时释放?

** 因为子线程的runloop默认是不开启的,需要我们在子线程获取runloop后,再进行开启。
所以如果不使用runloop,在子线程不创建自动释放池。
App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。
第一个Observer监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是 -2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。
第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和_objc_autoreleasePoolPush()释放旧的池并创建新池;Exit(即将退出Loop) 时调用_objc_autoreleasePoolPop()来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。
**

你可能感兴趣的:(AutoreleasePool源码)