AutoreleasePool 重新梳理

AutoreleasePool 是一个抽象概念,并没有实际结构,真实的结构是一个双向链表『AutoreleasePoolPage』,由C++实现。

1.数据结构

其数据结构如下:

class AutoreleasePoolPage 
{

#define POOL_SENTINEL nil
    static pthread_key_t const key = AUTORELEASE_POOL_KEY;
    static uint8_t const SCRIBBLE = 0xA3;  // 0xA3A3A3A3 after releasing
    static size_t const SIZE = 
#if PROTECT_AUTORELEASEPOOL
        PAGE_MAX_SIZE;  // must be multiple of vm page size
#else
        PAGE_MAX_SIZE;  // size and alignment, power of 2
#endif
    static size_t const COUNT = SIZE / sizeof(id);

    magic_t const magic;
    id *next;
    pthread_t const thread;
    AutoreleasePoolPage * const parent;
    AutoreleasePoolPage *child;
    uint32_t const depth;
    uint32_t hiwat;
}

成员变量说明:

next:游标,一直指向最新入栈的autorelease对象的下一个位置。

key:TLS技术,既Thread Local Storage(TLS)线程局部存储。目的很简单,将一块内存作为某个线程专有的存储,以key-value的形式进行读写。AutoreleasePoolPage将这块区域用作存储最新的Page,既hotPage。

SIZE:单个page的最大存储数量,AutoreleasePoolPage以双向链表的形式存在,但是单个page的存储是有限额的,(id *) ((uint8_t *)this+SIZE)

thread:当前线程pthread_self()

2.push和pop

当我们手动调用@autoreleasePool的时候,编译器会自动将大括号内的所有对象标记为autorelease前缀。AutoreleasePoolPage::autorelease((id)this)当前对象本身作为参数入参,不过在讨论对象的autorelease之前,编译器还插入了两个方法:

void *pool = objc_autoreleasePoolPush();
……
……
……
objc_autoreleasePoolPop(pool);

前者做了和对象的autorelease相同的事情:

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);
        }
    }
id *add(id obj)
    {
        assert(!full());
        unprotect();
        id *ret = next;  // faster than `return next-1` because of aliasing
        *next++ = obj;
        protect();
        return ret;
    }

主要就是移动游标,并且返回当前位置,这个返回参数的意义主要体现在

objc_autoreleasePoolPop(pool);的入参中,pool记录着一个pool的初始位置,根据这个位置和当前的hotPage位置,遍历中间所有的对象,进行释放。并且由于双向链表的结构,很容易跨page进行遍历。

你可能感兴趣的:(AutoreleasePool 重新梳理)