使用ARC,是不是有一个自动释放池为每个线程致命? [英] Using ARC, is it fatal not to have an autorelease pool for every thread?

查看:105
本文介绍了使用ARC,是不是有一个自动释放池为每个线程致命?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我阅读:


如果您在应用程序中创建了辅助线程,则需要为其提供自己的自动释放池。自动释放池及其包含的对象将在iOS 5开发人员菜谱中的


中进一步讨论。



我正在用ARC编译。我一直在创建许多后台线程,似乎我做得很好。我的后台线程都没有长时间运行。将所有这些对象释放,通过说,主线程的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: )())
{
// 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();
}
});
}

解决方案

如果你不为你的新线程创建一个自动释放池,至少要考虑一个程序员错误。你的程序的实现。经典的问题是泄露的对象,因此对象从未执行(可能是致命的)的对象 $ dealloc 。



在ARC下创建自动释放池的现代方法是:

  void MONThreadsEntry(){//<条目是例如。一个函数或方法
@autoreleasepool {
...在这里做你的工作...
}
}

更详细地说,autorelease池表现为线程本地堆栈 - 你可以push和pop,但是应该总是有一个在该线程上的任何东西之前自动释放。



您可能无法看到问题(例如在控制台或泄漏),如果您的想法创建线程使用更高级的异步机制,例如使用NSOperationQueue,或者底层实现创建了辅助线程和自己的自动释放池。



,而不是猜测什么时候创建autorelease池,只是学习在哪里需要创建它们,以及何时应该创建它们。它们都有明确的定义 - 没有必要猜测,并且没有必要害怕创建它们。



同样,你永远不需要创建一个autorelease池对于你的线程,如果你使用低级抽象,永远不会自动释放该线程上的对象。例如,pthread和pure C实现不需要麻烦自动释放池(除非你使用的一些API假设它们已经就位)。



即使主线程一个Cocoa应用程序需要一个自动释放池 - 它通常不是你写的东西,因为它存在于项目模板中。



更新 - 调度队列



为了响应更新的问题:是的,您仍然应该为您的程序创建自动释放池,这些程序在分派队列下运行 - 请注意,使用分派队列,不是创建线程,所以这是一个不同的问题,从原来的问题。原因:虽然分派队列 管理自动释放池,不保证它们被清空的时间/点。也就是说,你的对象将被释放(在某些时候),但你应该也在这个上下文中创建自动释放池,因为实现可以(在理论上)耗尽池每运行10,000个块,或大约每天。所以在这种情况下,它真的只是致命的场景,如当你最终消耗了太多的内存,或者当你的程序期望其对象将被以某种确定的方式被销毁 - 例如,你可以加载或处理图像如果这些图像的生命由于自动释放池而意外地延长,则背景和上升消耗了大量的存储器。另一个例子是共享资源或全局对象,您可以在其中响应通知或引入竞争条件,因为您的阻止本地对象的生命时间可能比您期望的长得多。还要记住,实现/频率是随意改变的,因为它的实现者认为合适。


I read this:

If you ever create a secondary thread in your application, you need to provide it with its own autorelease pool. Autorelease pools and the objects they contain are discussed further in

in the iOS 5 Developer cookbook.

I'm compiling with ARC. I have been creating many background threads, and it seems that I am doing fine. None of my background threads are long-running. Will all those objects ever be released by say, the main thread's autorelease pool? Or what?

This is what I do to call background thread:

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

Should I change that to

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

解决方案

Consider it at minimum a programmer error if you do not create an autorelease pool for your new thread. Whether that's fatal to your program is defined by your program's implementation. The classic problem is leaked objects and consequently objects' dealloc which is never executed (could be fatal).

The modern way to create an autorelease pool under ARC is:

void MONThreadsEntry() { // << entry is e.g. a function or method
  @autoreleasepool {
    ...do your work here...
  }
}

In more detail, autorelease pools behave as thread-local stacks -- you can push and pop, but there should always be one in place before anything on that thread is autoreleased. Autorelease messages are not transferred from one thread to another.

You may not see issues (e.g. in the console or leaks) if your idea of "creating a thread" is using a higher level asynchronous mechanism, such as using an NSOperationQueue, or if the underlying implementation creates a secondary thread and its own autorelease pool.

Anyways, rather than guessing when to create autorelease pools, just learn where you need to create them and when you should create them. It's all well-defined -- there is no need for guesswork, and there is no need to fear creating them.

Similarly, you will never need to create an autorelease pool for your thread if you are using lower level abstractions, and never autorelease objects on that thread. For example, pthreads and pure C implementations won't need to bother with autorelease pools (unless some API you use assumes they are in place).

Even the main thread in a Cocoa app needs an autorelease pool -- it's just typically not something you write because it exists in the project templates.

Update -- Dispatch Queues

In response to updated question: Yes, you should still create autorelease pools for your programs which run under dispatch queues -- note that with a dispatch queue, you're not creating threads so this is quite a different question from the original question. The reason: Although dispatch queues do manage autorelease pools, no guarantee is made regarding the time/point they are emptied. That is to say, your objects would be released (at some point), but you should also create autorelease pools in this context because the implementation could (in theory) drain the pool every 10,000 blocks it runs, or approximately every day. So in this context, it's really only fatal in scenarios such as when you end up consuming too much memory, or when your programs expects that its objects will be destroyed in some determined fashion -- for example, you could be loading or processing images in the background and wind up consuming a ton of memory if the life of those images is extended unexpectedly because of the autorelease pools. The other example is shared resources or global objects, where you could respond to notifications or introduce race conditions because your "block local" objects may live a lot longer than you expect. Also remember that the implementation/frequency is free to change as its implementors see fit.

这篇关于使用ARC,是不是有一个自动释放池为每个线程致命?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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