美文网首页
iOS autoreleasepool

iOS autoreleasepool

作者: GTMYang | 来源:发表于2018-06-05 13:32 被阅读0次

    1. 数据结构

    //  AutoreleasePoolPage对象
    class AutoreleasePoolPage 
    {
        static pthread_key_t const key = AUTORELEASE_POOL_KEY;
        magic_t const magic;
        id *next;                        // 自动回收对象栈的栈指针(相当于sp)
        pthread_t const thread;          // 当前回收迟对应的线程
        AutoreleasePoolPage * const parent;// parent页指针 链表指针
        AutoreleasePoolPage *child; // child页指针 链表指针
    }
    
    • parent和child使AutoreleasePoolPage对象组成一个双向链表
      双向链表
    • 栈(存储autorelease对象指针)
    AutoreleasePoolPage ->
     id *next; // 相当于栈指针sp
    
    // 看add方法
     id *add(id obj)
        {
            //assert(!full());
           // unprotect();
            id *ret = next;  // faster than `return next-1` because of aliasing
            *next++ = obj;
           // protect();
            return ret;
        }
    
    • 游标 hotPage()获取当前线程的当前AutoreleasePoolPage页
    // 获取当前线程的hotPage
     static inline AutoreleasePoolPage *hotPage() 
        {
            AutoreleasePoolPage *result = (AutoreleasePoolPage *)
                tls_get_direct(key);
            if (result) result->fastcheck();
            return result;
        }
    
    // 设置当前线程的hotPage
    static inline void setHotPage(AutoreleasePoolPage *page) 
        {
            if (page) page->fastcheck();
            tls_set_direct(key, (void *)page);
        }
    
    • POOL_SENTINEL哨兵
    #define POOL_SENTINEL nil // POOL_SENTINEL 这个很重要,是自动回收池栈帧的分隔符
    

    备注:TLS(线程独享存储技术)
    TSL的存储是每个线程独立的,互不干扰。
    TLS是线程局部存储(Thread Local Storage)的缩写,在oc中通过这两个方法来使用:

    static inline void *tls_get_direct(tls_key_t k) 
    { 
        assert(is_valid_direct_key(k));
    
        if (_pthread_has_direct_tsd()) {
            return _pthread_getspecific_direct(k);
        } else {
            return pthread_getspecific(k);
        }
    }
    
    static inline void tls_set_direct(tls_key_t k, void *value) 
    { 
        assert(is_valid_direct_key(k));
    
        if (_pthread_has_direct_tsd()) {
            _pthread_setspecific_direct(k, value);
        } else {
            pthread_setspecific(k, value);
        }
    }
    

    2.调用

    // @autoreleasepool {} 
    相当于 -->
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
         }
    struct __AtAutoreleasePool {
      __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
      ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
      void * atautoreleasepoolobj;
    };
    相当于 -->
       void * atautoreleasepoolobj = objc_autoreleasePoolPush();  
       // do whatever you want
       objc_autoreleasePoolPop(atautoreleasepoolobj);
    
    
    // 
    void *objc_autoreleasePoolPush(void) {
        return AutoreleasePoolPage::push();
    }
    void objc_autoreleasePoolPop(void *ctxt) {
        AutoreleasePoolPage::pop(ctxt); // 执行所有autorelease对象的release
    }
    

    对象调用autorelease的过程

    [obj autorelease] 相当于 --> AutoreleasePoolPage::autorelease(obj);
    // 
    static inline id autorelease(id obj)
        {
            id *dest __unused = autoreleaseFast(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); // 创建新的AutoreleasePoolPage,并add
            } else {
                return autoreleaseNoPage(obj); // 创建根AutoreleasePoolPage并add
            }
        }
    
    ///// autoreleaseNoPage
        id *autoreleaseNoPage(id obj)
        {
            // No pool in place.
            assert(!hotPage());
    
            if (obj != POOL_SENTINEL  &&  DebugMissingPools) {
                // We are pushing an object with no pool in place, 
                // and no-pool debugging was requested by environment.
                _objc_inform("MISSING POOLS: Object %p of class %s "
                             "autoreleased with no pool in place - "
                             "just leaking - break on "
                             "objc_autoreleaseNoPool() to debug", 
                             (void*)obj, object_getClassName(obj));
                objc_autoreleaseNoPool(obj);
                return nil;
            }
    
            // Install the first page.
            AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
            setHotPage(page);
    
            // Push an autorelease pool boundary if it wasn't already requested.
            if (obj != POOL_SENTINEL) {
                page->add(POOL_SENTINEL);
            }
    
            // Push the requested object.
            return page->add(obj);
        }
    

    push和pop

     static inline void *push() 
        {
            id *dest;
            if (DebugPoolAllocation) {
                // Each autorelease pool starts on a new pool page.
                dest = autoreleaseNewPage(POOL_SENTINEL);
            } else {
                dest = autoreleaseFast(POOL_SENTINEL);
            }
            assert(*dest == POOL_SENTINEL);
            return dest;
        }
    
        static inline void pop(void *token) 
        {
            AutoreleasePoolPage *page;
            id *stop;
    
            page = pageForPointer(token);
            stop = (id *)token;
            if (DebugPoolAllocation  &&  *stop != POOL_SENTINEL) {
                // This check is not valid with DebugPoolAllocation off
                // after an autorelease with a pool page but no pool in place.
                _objc_fatal("invalid or prematurely-freed autorelease pool %p; ", 
                            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();
                }
            }
        }
    

    关键字

    双向链表TLS(线程独享存储)分页的栈哨兵

    子线程与auotrelease

    相关文章

      网友评论

          本文标题:iOS autoreleasepool

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