美文网首页
4、autoreleasePool

4、autoreleasePool

作者: howhyone | 来源:发表于2022-07-16 20:02 被阅读0次

    关键字:autoreleasePoolpage组成的双向链表结构,
    1、enter (进入runloop) -> objc_autoreleasePoolPush()
    _BeforeWaiting(休眠前) ->objc_autoreleasePoolPush()、objc_autoreleasePoolPop()
    _Exit(离开) objc_autoreleasePoolPop()
    2、push:page->add(obj)、autoreleaseFullPage(obj, page);、autoreleaseNoPage(obj);
    pop:releaseUntil、page->kill(); setHotPage(parent);
    3、 autorelaeasepool、NSRunLoop 、子线程三者的关系
    1.主线程默认为我们开启 Runloop,Runloop 会自动帮我们创建Autoreleasepool,并进行Push、Pop 等操作来进行内存管理。
    2.子线程默认不开启runloop,当产生autorelease对象时候,会将对象添加到最近一次创建的autoreleasepool中,一般是main函数中的autoreleasepool,由主线程runloop管理;也就是不用手动创建Autoreleasepool,线程销毁时在会在最近一次创建的autoreleasepool 中释放对象。
    3.自定义的 NSOperation 和 NSThread 需要手动创建自动释放池。比如: 自定义的 NSOperation 类中的 main 方法里就必须添加自动释放池。否则出了作用域后,自动释放对象会因为没有自动释放池去处理它,而造成内存泄露。
    但对于 blockOperation 和 invocationOperation 这种默认的Operation ,系统已经帮我们封装好了,不需要手动创建自动释放池。
    4.AutoreleasePool是按线程一一对应的(结构中的thread指针指向当前线程),每开一个线程,会有与之对应的AutoreleasePool。

    autoreleasePoolPage结构

    struct AutoreleasePoolPageData
    {
        magic_t const magic;  // 校验atoreleasepool的完整性
        __unsafe_unretained id *next;  //下一个被添加对象的地址
        pthread_t const thread;  // 当前的线程
        AutoreleasePoolPage * const parent;  //前驱结点
        AutoreleasePoolPage *child;  //后继结点
        uint32_t const depth;  //链表深度,也是当前page在链表的位置
        uint32_t hiwat;   //hiwat:最大入栈数量标记
    };
    
    

    1、push

    void *
    objc_autoreleasePoolPush(void)
    {
        return AutoreleasePoolPage::push();
    }
    
        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;
        }
    
        static inline id *autoreleaseFast(id obj)
        {
            AutoreleasePoolPage *page = hotPage();
            if (page && !page->full()) {  // 有page,但是未满,直接添加
                return page->add(obj);
            } else if (page) {  // 有page满了,去出现子page
                return autoreleaseFullPage(obj, page);  
            } else {  // 没有page就创建新page,添加边界守卫(越界标识)和obj
                return autoreleaseNoPage(obj);
            }
        }
    
       static __attribute__((noinline))
       id *autoreleaseFullPage(id obj, AutoreleasePoolPage *page)
       {
           do { // 创建并添加子page
               if (page->child) page = page->child;
               else page = new AutoreleasePoolPage(page);
           } while (page->full());
           setHotPage(page); //  把子page设置为当前的page
           return page->add(obj);   // 添加对象到page中
       }
    
        id *add(id obj)
        {
            ret = next;  // faster than `return next-1` because of aliasing
            *next++ = obj; // 当前对象当道next上,然后next+1,方便存放下一个释放对象
    
            return ret;  // 返回释放对象的存放地址
        }
    

    2、pop

    objc_autoreleasePoolPop(void *ctxt)
    {
        AutoreleasePoolPage::pop(ctxt);
    }
    
        static void
        popPage(void *token, AutoreleasePoolPage *page, id *stop)
        {
            page->releaseUntil(stop);   // 删掉page中的对象
      // 删掉page,有parent就将其parent设置为hotpage,没有就将nil设置为hotpage
            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();
                }
            }
        }
    

    释放pool中的对象

        void releaseUntil(id *stop) 
        {        
            while (this->next != stop) { 
                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);
                }
    
    #if SUPPORT_AUTORELEASEPOOL_DEDUP_PTRS   // 支持删除重复数据
                AutoreleasePoolEntry* entry = (AutoreleasePoolEntry*) --page->next;
    
                // create an obj with the zeroed out top byte and release that
                id obj = (id)entry->ptr;
                int count = (int)entry->count;  // grab these before memset
    #else
                id obj = *--page->next; // 获取当前的对象
    #endif
                memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
    
                if (obj != POOL_BOUNDARY) {
    #if SUPPORT_AUTORELEASEPOOL_DEDUP_PTRS
                    // release count+1 times since it is count of the additional
                    // autoreleases beyond the first one
                    for (int i = 0; i < count + 1; i++) {
                        objc_release(obj); 
                    }
    #else
                    objc_release(obj); // 引用计数器 -1 
    #endif
                }
            }
    
            setHotPage(this);
    
    

    3、AutoReleasePool pop和push的时机

    在afterWaiting和exit状态时调用 autoreleasePoolPop,objc_release(obj),对象的引用计数-1,进行释放
    
    
    1、App启动后,系统在主线程RunLoop 里注册两个Observser,其回调都是_wrapRunLoopWithAutoreleasePoolHandler()。
    
    2、第一个 Observer 监视的事件
     是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其优先级最高,保证创建释放池发生在其他所有回调之前。
    
    3、第二个 Observer 监视了两个事件
    _BeforeWaiting(准备进入休眠) 时 _
     调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;
    _Exit(即将退出Loop) 时 _
     调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 优先级最低,保证其释放池子发生在其他所有回调之后。
    

    4、参数放入autoreleasepool的时机

    autorelease->....->rootAutorelease2 -> autoreleaseFast

    - (id)autorelease {
        return _objc_rootAutorelease(self);
    }
    
    __attribute__((noinline,used))
    id 
    objc_object::rootAutorelease2()
    {
        ASSERT(!isTaggedPointer());
        return AutoreleasePoolPage::autorelease((id)this);
    }
    
        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;
        }
    
        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);
            }
        }
    

    相关文章

      网友评论

          本文标题:4、autoreleasePool

          本文链接:https://www.haomeiwen.com/subject/zvkgvrtx.html