使用ARC,是不是每个线程都有一个自动释放池是致命的?
我读过这个:
如果您在应用程序中创build了辅助线程,则需要为其提供自己的autorelease池。 Autorelease池及其包含的对象将在下文进一步讨论
在iOS 5 Developer Cookbook中。
我正在编译ARC。 我一直在创build很多后台线程,而且看起来我很好。 我的后台线程都不是长时间运行的。 所有这些对象是否会被释放,主线程的autorelease池? 或者是什么?
这就是我所做的调用后台线程:
+(void)doBackground:(void (^)())block { //DISPATCH_QUEUE_PRIORITY_HIGH //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^{ dispatch_async(dispatch_get_global_queue(-2,0), ^{ block(); }); }
我应该改变它
+(void)doBackground:(void (^)())block { //DISPATCH_QUEUE_PRIORITY_HIGH //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^{ dispatch_async(dispatch_get_global_queue(-2,0), ^{ @autoreleasepool{ block(); } }); }
如果你不为你的新线程创build一个自动释放池,至less考虑一个程序员错误。 对程序来说是否致命是由程序的实现来定义的。 经典的问题是泄露的对象,因此对象的dealloc
永远不会执行(可能是致命的)。
在ARC下创build自动释放池的现代方法是:
void MONThreadsEntry() { // << entry is eg a function or method @autoreleasepool { ...do your work here... } }
更详细地说,自动释放池的行为与线程本地堆栈相同 – 您可以推送和popup,但在该线程上的任何内容自动释放之前,总是应该有一个。 自动释放消息不会从一个线程传输到另一个线程。
如果你的“创build线程”的想法是使用更高级别的asynchronous机制,比如使用NSOperationQueue,或者底层实现创build了一个辅助线程和自己的自动释放池,那么你可能看不到问题(例如在控制台或者泄漏中) 。
无论如何,不要猜测什么时候创build自动释放池,只需要学习创build它们的位置,以及何时创build它们。 这一切都是明确的 – 没有必要猜测,也没有必要担心创造它们。
同样,如果您使用较低级别的抽象,则永远不需要为您的线程创build自动释放池,也不会在该线程上自动释放对象。 例如,pthread和纯C实现将不需要打扰autorelease池(除非你使用的某些API假设它们已经到位)。
即使Cocoa应用程序的主线程也需要一个自动释放池 – 这通常不是你写的东西,因为它存在于项目模板中。
更新 – 调度队列
为了回应更新的问题:是的,你仍然应该为在你的程序下运行的程序创build自动释放池 – 注意,使用一个分派队列,你不会创build线程,所以这是一个与原始问题完全不同的问题。 原因:虽然派遣队列pipe理自动释放池,但不能保证它们被清空的时间/点。 也就是说,你的对象会被释放(在某些时候),但是你也应该在这个上下文中创build自动释放池,因为实现可能(理论上)每运行10000个块,或者大约每天都会耗尽池。 因此,在这种情况下,在诸如最终消耗太多内存的情况下,或者当程序期望以某种确定的方式销毁其对象时,实际上这只会是致命的 – 例如,您可能正在加载或处理图像如果这些图像的生命由于自动释放池而意外延长,那么背景消失并消耗大量的内存。 另一个例子是共享资源或全局对象,在那里你可以响应通知或引入竞争条件,因为你的“块本地”对象可能比你想象的要长得多。 另外请记住,执行者/执行者的频率可以随着执行者认为合适而自由改变。
现在看来自动释放池是为新线程自动创build的。 不知道这是什么时候改变的,为什么说文档是相反的,但就是这样。