# 问题: iOS 子线程默认不会开启 Runloop,那出现 Autorelease 对象如何处理

4,158 阅读3分钟
  • Autoreleasepool 与 Runloop 的关系及Autoreleasepool的数据结构
  • ARC 下什么样的对象由 Autoreleasepool 管理
  • 子线程默认不会开启 Runloop,那出现 Autorelease 对象如何处理?不手动处理会内存泄漏吗?

下面是这三个问题的答案

  1. 主线程默认为我们开启 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是虚拟内存一页的大小
  1. 借用网上的答案 虽然在程序入口,已经帮我们加上了 autoreleasepool,但是并不是说大括号内的所有 对象都会交给autoreleasepool来处理
  • 当使用alloc/new/copy/mutableCopy开始的方法进行初始化时,会生成并持有对象(也就是不需要pool管理,系统会自动的帮他在合适位置release)
  • __weak修饰符只持有对象的弱引用,而在访问引用对象的过程中,该对象可能被废弃。那么如果把对象注册到autorealeasepool中,那么在@autorealeasepool块结束之前都能确保对象的存在。最新的情况是weak修饰的对象不会再被加入到Pool了
  1. 在子线程你创建了 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);
    ```