NSThread现在会自动创建autoreleasepool吗?

eli*_*nis 8 nsthread nsautoreleasepool ios

我有这样的测试代码

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];
    [thread start];
}

-(void)test
{
    MyClass *my = [[[MyClass alloc] init] autorelease];
    NSLog(@"%@",[my description]);
}
Run Code Online (Sandbox Code Playgroud)

我没有为自己的线程创建任何自动释放池,但是当线程退出时,对象"我的"只是dealloc.why?

即使我改变我的测试代码如下

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil];
    [thread start];
} 

-(void)test
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    MyClass *my = [[[MyClass alloc] init] autorelease];
    NSLog(@"%@",[my description]);
}
Run Code Online (Sandbox Code Playgroud)

我创建了自己的autoreleasepool但在线程退出时不会将其耗尽.无论如何,对象"我的"仍然可以dealloc.为什么?

我使用Xcode5而不使用ARC

use*_*008 23

它没有记录,但在OS X 10.9+和iOS 7+上答案似乎是肯定的.

Objective-C运行时是开源的,因此您可以阅读源代码以查看正在进行的操作.如果autorelease在当前线程上执行没有池的话,最新版本的运行时(646,OS X 10.10和iOS 8附带)确实添加了一个池.在NSObject.mm中:

static __attribute__((noinline))
id *autoreleaseNoPage(id obj)
{
    // No pool in place.
    assert(!hotPage());

    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.
    AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
    setHotPage(page);

    // Push an autorelease pool boundary if it wasn't already requested.
    if (obj != POOL_SENTINEL) {
        page->add(POOL_SENTINEL);
    }

    // Push the requested object.
    return page->add(obj);
}
Run Code Online (Sandbox Code Playgroud)

当您按下第一个池时(在这种情况下推送的东西是POOL_SENTINEL),或者您在没有池的情况下自动释放,就会调用此函数.当推送第一个池时,它会设置自动释放堆栈.但是从代码中可以看出,只要DebugMissingPools没有设置环境变量(默认情况下没有设置),当autorelease完成没有池时,它也会设置自动释放堆栈,然后推送一个池(推送一个POOL_SENTINEL) .

类似地,(在没有查看其他代码的情况下有点难以理解,但这是相关部分)当线程被销毁(并且线程局部存储被销毁)时,它会释放自动释放堆栈中的所有内容(这就是pop(0);所以它不依赖于用户弹出最后一个池:

static void tls_dealloc(void *p) 
{
    // reinstate TLS value while we work
    setHotPage((AutoreleasePoolPage *)p);
    pop(0);
    setHotPage(nil);
}
Run Code Online (Sandbox Code Playgroud)

之前版本的运行时(551.1,OS X 10.9和iOS 7附带)也是这样做的,你可以从它的NSObject.mm看到:

static __attribute__((noinline))
id *autoreleaseSlow(id obj)
{
    AutoreleasePoolPage *page;
    page = hotPage();

    // The code below assumes some cases are handled by autoreleaseFast()
    assert(!page || page->full());

    if (!page) {
        // No pool. Silently push one.
        assert(obj != POOL_SENTINEL);

        if (DebugMissingPools) {
            _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;
        }

        push();
        page = hotPage();
    }

    do {
        if (page->child) page = page->child;
        else page = new AutoreleasePoolPage(page);
    } while (page->full());

    setHotPage(page);
    return page->add(obj);
}
Run Code Online (Sandbox Code Playgroud)

但之前的版本(532.2,OS X 10.8和iOS 6附带)并没有:

static __attribute__((noinline))
id *autoreleaseSlow(id obj)
{
    AutoreleasePoolPage *page;
    page = hotPage();

    // The code below assumes some cases are handled by autoreleaseFast()
    assert(!page || page->full());

    if (!page) {
        assert(obj != POOL_SENTINEL);
        _objc_inform("Object %p of class %s autoreleased "
                     "with no pool in place - just leaking - "
                     "break on objc_autoreleaseNoPool() to debug", 
                     obj, object_getClassName(obj));
        objc_autoreleaseNoPool(obj);
        return NULL;
    }

    do {
        if (page->child) page = page->child;
        else page = new AutoreleasePoolPage(page);
    } while (page->full());

    setHotPage(page);
    return page->add(obj);
}
Run Code Online (Sandbox Code Playgroud)

请注意,上述适用于任何pthreads,而不仅仅是NSThreads.

所以基本上,如果你在OS X 10.9+或iOS 7+上运行,在没有池的线程上自动释放不应该导致泄漏.这没有记录,并且是内部实现细节,因此请谨慎依赖此,因为Apple可能会在未来的操作系统中更改它.但是,我没有看到任何理由为什么他们会删除此功能,因为它很简单,只有好处而且没有缺点,除非他们完全重写自动释放池的工作方式或其他方式.


Raj*_*esh 1

苹果文档说(第4):

\n\n
\n

您可以使用NSAutoreleasePool通常的 alloc 和 init 消息创建一个对象,并使用排出(或释放 xe2x80x94 要了解差异,请参阅垃圾收集)来处理它。由于您无法保留自动释放池(或自动释放它\xe2\x80\x94请参阅保留和自动释放),\n 耗尽池最终会产生释放池的效果。您应该始终在创建的同一上下文(方法或函数的调用,或循环体)中耗尽自动释放池。有关更多详细信息,请参阅使用自动释放池块。

\n
\n