- Autoreleasepool 与 Runloop 的关系及Autoreleasepool的数据结构
- ARC 下什么样的对象由 Autoreleasepool 管理
- 子线程默认不会开启 Runloop,那出现 Autorelease 对象如何处理?不手动处理会内存泄漏吗?
下面是这三个问题的答案
- 主线程默认为我们开启 Runloop,Runloop 会自动帮我们创建Autoreleasepool,并进行Push、Pop 等操作来进行内存管理,具体大家可以看Autorealsepool的数据结构
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
void *objc_autoreleasePoolPush(void) {
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt) {
AutoreleasePoolPage::pop(ctxt);
}
- 不难看出Autorealsepool的主要底层数据结构是:__AtAutoreleasePool、AutoreleasePoolPage调用了autorelease的对象最终都是通过AutoreleasePoolPage对象来管理的,AutoreleasePoolPage的数据结构是双向链表,其中根据哨兵来进行push和pop release的对象,具体的不详细讲解了,网上都能找到答案
- 提出个小小疑问,大家有没有想过,为什么每个AutoreleasePoolPage的大小设置成4096个字节呢? 因为4096是虚拟内存一页的大小
- 借用网上的答案
虽然在程序入口,已经帮我们加上了 autoreleasepool,但是并不是说大括号内的所有
对象都会交给autoreleasepool来处理
- 当使用alloc/new/copy/mutableCopy开始的方法进行初始化时,会生成并持有对象(也就是不需要pool管理,系统会自动的帮他在合适位置release)
- __weak修饰符只持有对象的弱引用,而在访问引用对象的过程中,该对象可能被废弃。那么如果把对象注册到autorealeasepool中,那么在@autorealeasepool块结束之前都能确保对象的存在。最新的情况是weak修饰的对象不会再被加入到Pool了
- 在子线程你创建了 Pool 的话,产生的 Autorelease 对象就会交给 pool 去管理。如果你没有创建 Pool ,但是产生了 Autorelease 对象,就会调用 autoreleaseNoPage 方法。在这个方法中,会自动帮你创建一个 hotpage(hotPage 可以理解为当前正在使用的 AutoreleasePoolPage,如果你还是不理解,可以先看看 Autoreleasepool 的源代码,再来看这个问题 ),并调用 page->add(obj)将对象添加到 AutoreleasePoolPage 的栈中,也就是说你不进行手动的内存管理,也不会内存泄漏啦!StackOverFlow 的作者也说道,这个是 OS X 10.9+和 iOS 7+ 才加入的特性。
static __attribute__((noinline))
id *autoreleaseNoPage(id obj)
{
// No pool in place.
// hotPage 可以理解为当前正在使用的 AutoreleasePoolPage。
assert(!hotPage());
// POOL_SENTINEL 只是 nil 的别名
if (obj != POOL_SENTINEL && DebugMissingPools) {
// We are pushing an object with no pool in place,
// and no-pool debugging was requested by environment.
_objc_inform("MISSING POOLS: Object %p of class %s "
"autoreleased with no pool in place - "
"just leaking - break on "
"objc_autoreleaseNoPool() to debug",
(void*)obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return nil;
}
// Install the first page.
// 帮你创建一个 hotpage(hotPage 可以理解为当前正在使用的 AutoreleasePoolPage
AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
setHotPage(page);
// Push an autorelease pool boundary if it wasn't already requested.
// POOL_SENTINEL 只是 nil 的别名,哨兵对象
if (obj != POOL_SENTINEL) {
page->add(POOL_SENTINEL);
}
// Push the requested object.
// 把对象添加到 自动释放池 进行管理
return page->add(obj);
```