pop(void *token)
static inline void pop(void *token)
{
AutoreleasePoolPage *page;
id *stop;
if (token == (void*)EMPTY_POOL_PLACEHOLDER) {
// Popping the top-level placeholder pool.
if (hotPage()) {
// Pool was used. Pop its contents normally.
// Pool pages remain allocated for re-use as usual.
pop(coldPage()->begin());
} else {
// Pool was never used. Clear the placeholder.
setHotPage(nil);
}
return;
}
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);
}
}
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();
}
}
}
如果传入token为EMPTY_POOL_PLACEHOLDER并且当前存在AutoreleasePoolPage就从最顶层父AutoreleasePoolPage的begin位开始pop;如果当前不存在AutoreleasePoolPage则表明未使用AutoreleasePool,所以重置当前AutoreleasePoolPage并且直接return
如果传入的非EMPTY_POOL_PLACEHOLDER,则通过函数pageForPointer来查找具体在哪个AutoreleasePoolPage中。
如果stop不为POOL_BOUNDARY
stop为起始位并且无父AutoreleasePoolPage
处理新老SDK的兼容问题
从当前AutoreleasePoolPage向前release对象,直到stop
Debug模式并且当前AutoreleasePoolPage为空
删除所有子AutoreleasePoolPage
重新配置当前AutoreleasePoolPage
pop所有对象时
删除所有子AutoreleasePoolPage
重新配置当前AutoreleasePoolPage
如果存在子AutoreleasePoolPage
如果stop所在AutoreleasePoolPage存储对象少于一半则删除子AutoreleasePoolPage的子AutoreleasePoolPage
否则删除....(好绕口,这里应该是根据当前存储情况删除未使用到的空AutoreleasePoolPage)
由转换的c++代码我们可以看出objc_autoreleasePoolPop的参数即objc_autoreleasePoolPush生成的变量,所以@autoreleasePool block在出了其作用域时都会将自身包裹的autoreleased对象进行出栈操作
objc_autoreleasePoolPush()
objc_autoreleasePoolPop(atautoreleasepoolobj)
两个函数我们都基本分析完了,现在我们看看在这个两个函数之间的对象调用autorelease的流程
- (id)autorelease {
return ((id)self)->rootAutorelease();
}
inline id objc_object::rootAutorelease()
{
if (isTaggedPointer()) return (id)this;
if (prepareOptimizedReturn(ReturnAtPlus1)) return (id)this;
return rootAutorelease2();
}
这里我们看到TaggedPointer是直接返回的,也验证了之前所说的NSString问题。
prepareOptimizedReturn属于TLS优化部分我们先放放
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;
}
我们看到autorelease方法其实也是调用之前的autoreleaseFast函数进行对象入栈操作的 |