各个线程 Autorelease 对象的内存管理

最近和 bestswifterkuailejim 搞了一套模拟面试,而后无论是应届生仍是工做两三年的高级工程师都对下面这几个问题比较懵逼,多是开发中用到的很少,在这里浅浅的讨论下面试

  • Autoreleasepool 与 Runloop 的关系
  • ARC 下什么样的对象由 Autoreleasepool 管理
  • 子线程默认不会开启 Runloop,那出现 Autorelease 对象如何处理?不手动处理会内存泄漏吗?

针对第一个问题,比较容易理解,能够看一下:ibireme深刻理解RunLoop,主线程默认为咱们开启 Runloop,Runloop 会自动帮咱们建立Autoreleasepool,并进行Push、Pop 等操做来进行内存管理swift

第二个问题,ARC 下什么样的对象由 Autoreleasepool 管理呢?大多数人的回答是:“都会由 pool 进行管理”。其实并非这样的,对于普通的对象是由编译器在合适的地方为咱们 Realease 了。针对这个问题,我已经总结过:引用计数带来的一次讨论,是参考了经典的《iOS与OS X多线程和内存管理 》这本书。bash

针对第三个问题,感受比较难以回答,须要很细致的读过 Runtime 、Autoreleasepool 的源码才能够。我也是参考了 StackOverFlow 的回答:does NSThread create autoreleasepool automaticly now?。我再来简单阐述下,在子线程你建立了 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); }复制代码

Reference

相关文章
相关标签/搜索