NSThread现在会自动创建autoreleasepool吗? [英] does NSThread create autoreleasepool automatically now?

查看:97
本文介绍了NSThread现在会自动创建autoreleasepool吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的测试代码

- (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]);
}

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

I did not create any autoreleasepool for my own thread, but when the thread exit, object "my" just dealloc.why?

即使我将测试代码更改如下

even though I change my test code as below

- (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]);
}

我创建了自己的自动释放池,但在线程退出时不会耗尽它。对象我的仍然可以dealloc。为什么?

I create my own autoreleasepool but not drain it when the thread exit. object "my" can still dealloc anyway. why?

我使用Xcode5而不使用ARC

I use Xcode5 and not using ARC

推荐答案

这是没有记录,但在OS X 10.9+和iOS 7 +上答案似乎是

It's not documented, but the answer appears to be Yes, on OS X 10.9+ and iOS 7+.

Objective-C运行时是< a href =http://www.opensource.apple.com/source/objc4/ =noreferrer> open-source 所以你可以阅读源代码来看看发生了什么。如果在当前线程上执行 autorelease 而没有池,则运行时的最新版本(646,OS X 10.10和iOS 8附带)确实会添加池。在 NSObject.mm 中:

The Objective-C runtime is open-source so you can read the source to see what's going on. The latest version of the runtime (646, which shipped with OS X 10.10 and iOS 8) does indeed add a pool if you perform an autorelease without a pool on the current thread. In 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);
}

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

This function is called when you push the first pool (in which case the thing pushed is POOL_SENTINEL), or you autorelease with no pool. When the first pool is pushed, it sets up the autorelease stack. But as you see from the code, as long as the DebugMissingPools environmental variable is not set (it's not set by default), when autorelease is done with no pool, it also sets up the autorelease stack, and then pushes a pool (pushes a POOL_SENTINEL).

同样,(它有点)很难跟随而不看其他代码,但这是相关部分)当线程被销毁(并且线程局部存储被销毁)时,它会释放自动释放堆栈中的所有内容(这就是 pop(0); 确实如此)所以它不依赖于用户弹出最后一个池:

Similarly, (it's a little hard to follow without looking at the other code, but this is the relevant part) when the thread is destroyed (and the Thread-Local Storage is destroyed), it releases everything in the autorelease stack (that's what the pop(0); does) so it doesn't rely on the user to pop the last pool:

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

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

The previous version of the runtime (551.1, which came with OS X 10.9 and iOS 7), also did this, as you can see from its 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);
}

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

But the version before that (532.2, which came with OS X 10.8 and iOS 6), does not:

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);
}

请注意,以上适用于任何 pthread s,而不仅仅是 NSThread s。

Note that the above works for any pthreads, not just NSThreads.

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

So basically, if you are running on OS X 10.9+ or iOS 7+, autoreleasing on a thread without a pool should not lead to a leak. This is not documented and is an internal implementation detail, so be careful relying on this as Apple could change it in a future OS. However, I don't see any reason why they would remove this feature as it is simple and only has benefits and no downsides, unless they completely re-write the way autorelease pools work or something.

这篇关于NSThread现在会自动创建autoreleasepool吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆