Board logo

标题: AutoreleasePool从入门到放弃(3) [打印本页]

作者: look_w    时间: 2019-3-8 19:33     标题: AutoreleasePool从入门到放弃(3)

3. AutoreleasePool源码解析

AutoreleasePool源码可以从Runtime源码中获得。下载好我们可以在NSObject.mm中看到AutoreleasePool的实现原理和结构说明:

    Autorelease pool implementation
    A thread's autorelease pool is a stack of pointers. Each pointer is either an object to release, or POOL_BOUNDARY which is an autorelease pool boundary.
    A pool token is a pointer to the POOL_BOUNDARY for that pool. When the pool is popped, every object hotter than the sentinel is released.
    The stack is divided into a doubly-linked list of pages. Pages are added and deleted as necessary.
    Thread-local storage points to the hot page, where newly autoreleased objects are stored.

AutoreleasePool其实是一个存贮指针的栈,内部指针代表延迟释放的对象或者是表示不同AutoreleasePool之间的边界对象。
AutoreleasePool的token指针名为POOL_BOUNDARY,当AutoreleasePool执行Pop操作时后于POOL_BOUNDARY入栈的对象将被释放。
AutoreleasePool是由多页的双向列表页组成,列表页在必要时可添加与删除。
TLS(Thread-local storage)指向autoreleased最近存储的AutoreleasePool

    class AutoreleasePoolPage
    {
        ...
        magic_t const magic;                   //校验AutoreleasePoolPage完整性
        id *next;                              //存放下一个autoreleased对象地址
        pthread_t const thread;                //对应线程
        AutoreleasePoolPage * const parent;    //父AutoreleasePoolPage
        AutoreleasePoolPage *child;            //子AutoreleasePoolPage
        uint32_t const depth;                  //当前AutoreleasePoolPage索引index
        uint32_t hiwat;                        //存储autoreleased对象峰值数                        
        ...
    }

接下来我们分析在使用@autoreleasepool block时代码的具体执行。我们先从每个Cocoa Touch工程都包含的Main.m文件入手,cd到Main.m路径下再通过命令行来将代码转成c++形式

clang -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.3.sdk main.m

我们可以看到原本的代码被转换成:

    int main(int argc, char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
            return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));
        }
    }

而结构体__AtAutoreleasePool的定义我们也可以在转换代码中找到:

    struct __AtAutoreleasePool {
      __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
      ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
      void * atautoreleasepoolobj;
    };

由此我们可以知道__AtAutoreleasePool结构体在初始化和析构时分别执行了objc_autoreleasePoolPush和objc_autoreleasePoolPop(atautoreleasepoolobj)函数。我们先从这两个函数开始分析:(函数源码可以在之前的NSObject.mm文件中查找到)
objc_autoreleasePoolPush(void)

    void *objc_autoreleasePoolPush(void)
    {
        return AutoreleasePoolPage::push();
    }

push()

    static inline void *push()
        {
            id *dest;
            if (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;
        }

    Debug模式
        autoreleaseNewPage(POOL_BOUNDARY);
    非Debug模式下
        autoreleaseFast(POOL_BOUNDARY);

返回空池标志位或者AutoreleasePool边界对象




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0