staticinlinevoid *push(){
id *dest;
if (slowpath(DebugPoolAllocation)) {
// Each autorelease pool starts on a new pool page.//每一个释放池开始的时候都会创建一个新的page
dest = autoreleaseNewPage(POOL_BOUNDARY);
} else {
//快速的添加哨兵对象nil
dest = autoreleaseFast(POOL_BOUNDARY);//哨兵对象
}
ASSERT(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
return dest;
}
id *add(id obj)//像当前链表插入objc{
ASSERT(!full());
unprotect();//解除保护
id *ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;// 将obj入栈到栈顶并重新定位栈顶
protect();
return ret;
}
staticvoidpopPage(void *token, AutoreleasePoolPage *page, id *stop){
if (allowDebug && PrintPoolHiwat) printHiwat();// 记录最高水位标记
page->releaseUntil(stop);// 从栈顶开始操作出栈,并向栈中的对象发送release消息,直到遇到第一个哨兵对象// memory: delete empty children// 删除空掉的节点if (allowDebug && DebugPoolAllocation && page->empty()) {
// special case: delete everything during page-per-pool debugging
AutoreleasePoolPage *parent = page->parent;
page->kill();
setHotPage(parent);
} elseif (allowDebug && DebugMissingPools && page->empty() && !page->parent) {
// special case: delete everything for pop(top)// when debugging missing autorelease pools
page->kill();
setHotPage(nil);
} elseif (page->child) {
// hysteresis: keep one empty child if page is more than half fullif (page->lessThanHalfFull()) {
page->child->kill();
}
elseif (page->child->child) {
page->child->child->kill();
}
}
}
page->releaseUntil(stop)
voidreleaseUntil(id *stop){
// Not recursive: we don't want to blow out the stack // if a thread accumulates a stupendous amount of garbagewhile (this->next != stop) {
// Restart from hotPage() every time, in case -release // autoreleased more objects
AutoreleasePoolPage *page = hotPage();
// fixme I think this `while` can be `if`, but I can't prove itwhile (page->empty()) {
page = page->parent;
setHotPage(page);
}
page->unprotect();
id obj = *--page->next;
memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
page->protect();
if (obj != POOL_BOUNDARY) {
objc_release(obj);//不是哨兵对象就退出
}
}
setHotPage(this);
#if DEBUG// we expect any children to be completely emptyfor (AutoreleasePoolPage *page = child; page; page = page->child) {
ASSERT(page->empty());
}
#endif
}
staticinline id autorelease(id obj){
ASSERT(obj);
ASSERT(!obj->isTaggedPointer());
id *dest __unused = autoreleaseFast(obj);//
ASSERT(!dest || dest == EMPTY_POOL_PLACEHOLDER || *dest == obj);
return obj;
}