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.
//入栈 static inline void *push() { id *dest; //判断是否有pool if (slowpath(DebugPoolAllocation)) { // Each autorelease pool starts on a new pool page // 自动释放池从新池页面开始 //如果没有,则创建 dest = autoreleaseNewPage(POOL_BOUNDARY); } else { //压栈一个POOL_BOUNDARY,即压栈哨兵 dest = autoreleaseFast(POOL_BOUNDARY); } ASSERT(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY); return dest; }
//******** autoreleaseNoPage方法 ******** 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());
bool pushExtraBoundary = false; //判断是否是空占位符,如果是,则压栈哨兵标识符置为YES 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; } //如果对象不是哨兵对象,且没有Pool,则报错 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; } //如果对象是哨兵对象,且没有申请自动释放池内存,则设置一个空占位符存储在tls中,其目的是为了节省内存 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); //设置page为当前聚焦页 setHotPage(page); // Push a boundary on behalf of the previously-placeholder'd pool. //压栈哨兵的标识符为YES,则压栈哨兵对象 if (pushExtraBoundary) { //压栈哨兵 page->add(POOL_BOUNDARY); } // Push the requested object or pool. //压栈对象 return page->add(obj); }
//添加自动释放对象,当页满的时候调用这个方法 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-while遍历循环查找界面是否满了 do { //如果子页面存在,则将页面替换为子页面 if (page->child) page = page->child; //如果子页面不存在,则新建页面 else page = new AutoreleasePoolPage(page); } while (page->full());
//出栈 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. //如果当前页存在,则将当前页设置为coldPage,token设置为coldPage的开始位置 page = coldPage(); token = page->begin(); } else { //获取token所在的页 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); } }
//释放到stop位置之前的所有对象 void releaseUntil(id *stop) { // Not recursive: we don't want to blow out the stack // 不是递归的:我们不想破坏堆栈 // if a thread accumulates a stupendous amount of garbage //判断下一个对象是否等于stop,如果不等于,则进入while循环 while (this->next != stop) { // Restart from hotPage() every time, in case -release // autoreleased more objects 每次从hotPage()重新启动,以防-release自动释放更多对象 //获取当前操作页面,即hot页面 AutoreleasePoolPage *page = hotPage();
// fixme I think this `while` can be `if`, but I can't prove it //如果当前页是空的 while (page->empty()) { //将page赋值为父节点页 page = page->parent; //并设置当前页为父节点页 setHotPage(page); }
#if DEBUG // we expect any children to be completely empty for (AutoreleasePoolPage *page = child; page; page = page->child) { ASSERT(page->empty()); } #endif }
//销毁 void kill() { // Not recursive: we don't want to blow out the stack // if a thread accumulates a stupendous amount of garbage AutoreleasePoolPage *page = this; //获取最后一个页 while (page->child) page = page->child;
inline id objc_object::rootAutorelease() { // 是否为小对象 if (isTaggedPointer()) return (id)this; if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;
return rootAutorelease2(); }
对象执行rootAutorelease2
1 2 3 4 5 6 7
__attribute__((noinline,used)) id objc_object::rootAutorelease2() { ASSERT(!isTaggedPointer()); return AutoreleasePoolPage::autorelease((id)this); }
最后执行的还是AutoreleasePoolPage这个对象,调用autorelease
1 2 3 4 5 6 7 8 9
public: 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; }