1.申明了一个对象__autoreleasepool 相当于调用了objc_autoreleasePoolPush();
该函数的作用是向栈内压入一个"自动释放池"
2.当init main()函数执行完毕后,就会执行__autoreleasepool的析构函数objc_autoreleasePoolPop(atautoreleasepoolobj)用于释放“自动释放池”;
所以main()函数里可以大致这样理解:
AutoreleasePool 本质
AutoreleasePool实质上是一个双向AutoreleasePoolPage列表
创建自动释放池
void* objc_autoreleasePoolPush()内部实际调用的是AutoreleasePoolPage::push()函数
static inline void *push()
{
if (!hotPage()) {
setHotPage(new AutoreleasePoolPage(NULL));
}
id *dest = autoreleaseFast(POOL_SENTINEL);
assert(*dest == POOL_SENTINEL);
return dest;
}
hotpage :当前正在使用的page ,第一次使用hotPage 是NULL,所以新建一个parent=NULL的AutoreleasePoolPage对象作为自动释放池加入栈中,并将其设置为hotPage,然后返回POOL_SENTINEL的地址赋值给main()函数里的变量 __autoreleasepool;
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj);
} else {
return autoreleaseSlow(obj);
}
}
添加对象进自动释放池
可以看出,如果当前有page并且没有满,则直接将对象压入栈顶(page->add(obj)):
id *add(id obj)
{
assert(!full());
unprotect();
*next++ = obj;
protect();
return next-1;
}
然后将栈顶指针下移;
如果上述autoreleaseFast(id obj)中的page已经满了,则执行autoreleaseSlow(obj)
id *autoreleaseSlow(id obj)
{
AutoreleasePoolPage *page;
page = hotPage();
//如果没有page,则新建一个自动释放池,并添加obj对象进释放池
if (!page) {
objc_autoreleaseNoPool(obj);
return NULL;
}
//如果当前hotPage已经满了,则以链表的形式新增一个page并添加到当前page的后面,然后将此设置为hotPage;
do {
if (page->child) page = page->child;
else page = new AutoreleasePoolPage(page);
} while (page->full());
setHotPage(page);
return page->add(obj);
}
简单来说:如果page不存在则创建一个自动释放池,并将对象加入池内,
如果已经存在自动释放池在栈中,且hotPage满了,则遍历其子page,如果存在没满(page->full()==NO)的子page,则将该子page设置为hotPage,否则如果都满了,则以最后一个子page为父page,新建一个page,插入当前的page链表,同样设置该新建的page为hotPage,然后将自动释放对象加入pagel
销毁自动释放池
销毁自动释放池的调用方式是:
void AutoreleasePoolPage::pop(void *token)
token 即push()的返回值,实际上就是POOL_SENTINEL的地址(__autoreleasepool);通过该地址即可找到所在Page的地址指针,
static inline void pop(void *token)
{
AutoreleasePoolPage *page;
id *stop;
if (token) {
page = pageForPointer(token); //找到所在的page地址
stop = (id *)token; //POOL_SENTINEL的地址,从栈顶释放对象直到这个位置
} else {
// Token 0 is top-level pool
page = coldPage();
stop = page->begin();
}
page->releaseUntil(stop); //对自动释放池中对象调用objc_release()进行释放
// memory: delete empty children
// hysteresis: keep one empty child if this page is more than half full
// special case: delete everything for pop(0)
if (!token) {
page->kill();
setHotPage(NULL);
} else if (page->child) {
if (page->lessThanHalfFull()) {
page->child->kill();
}
else if (page->child->child) {
page->child->child->kill();
}
}
}
一、page->releaseUntil(stop),对栈顶(page->next)到stop地址(POOL_SENTINEL)之间的所有对象调用objc_release(),进行引用计数减1;
二、清空page对象page->kill(),有两句注释
// hysteresis: keep one empty child if this page is more than half full
// special case: delete everything for pop(0)
除非是pop(0)方式调用,这样会清理掉所有page对象;否则,在当前page存放的对象大于一半时,会保留一个空的子page,这样估计是为了可能马上需要新建page节省创建page的开销吧.