NSThread现在自动创buildautoreleasepool吗?

我有这样的testing代码

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

我没有为我自己的线程创build任何autoreleasepool,但是当线程退出时,对象“我的”只是dealloc.why?

即使我改变我的testing代码如下

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

我创build自己的autoreleasepool,但不排空线程退出时。 对象“我的”仍然可以dealloc。 为什么?

我使用Xcode5而不使用ARC

它没有logging,但答案似乎 ,在OS X 10.9 +和iOS 7 +上。

Objective-C运行时是开源的,所以你可以阅读源代码来看看发生了什么。 最新版本的运行时(OS X 10.10和iOS 8附带的646)确实会添加一个池,如果您在当前线程上执行不带池的autorelease 。 在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 ),或者你自动释放没有池时,这个函数被调用。 当第一个池被推入时,它设置了autorelease堆栈。 但是从代码中可以看出,只要DebugMissingPools环境variables没有被设置(默认情况下它没有设置),autorelease在没有池的情况下也会设置autorelease堆栈,然后推入一个pool(push a POOL_SENTINEL )。

同样的,当线程被销毁(线程本地存储被销毁)时,它会释放autorelease栈中的所有东西(这就是pop(0); )),所以它不依赖于用户popup最后一个池:

 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中看到:

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

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

 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。

所以基本上,如果你在OS X 10.9+或iOS 7+上运行,在没有池的线程上自动释放不应该导致泄漏。 这是没有logging,是一个内部的实现细节,所以要小心依靠这个苹果可以改变它在未来的操作系统。 但是,我不明白为什么他们会删除这个function,因为它很简单,只有优点和缺点,除非他们完全重写autorelease池的工作方式。

苹果文档说 (第四段):

你用通常的alloc和init消息创build一个NSAutoreleasePool对象,并使用drain(或release)来处理它,了解它们之间的区别,参见垃圾收集。 既然你不能保留一个自动释放池(或者自动释放它,请参阅retain和autorelease),排除一个池最终会释放它。 您应该始终在自己创build的同一个上下文中调用一个自动释放池(调用一个方法或函数,或者一个循环体)。 有关更多详细信息,请参阅使用自动释放池块。