Does Nsthread Create Autoreleasepool Automatically Now

Using ARC, is it fatal not to have an autorelease pool for every thread?

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.

Do I need an autoreleasepool block inside a DispatchQueue.main.async

DispatchQueue has an "autorelease frequency" attribute, which decides if every workitem is automatically surrounded by autorelease{} or not. It's documented in dispatch/queue.h and not in Apple's documentation, so I can't link to it; attaching screenshots from the headers.

  • DispatchQueue.main has autorelease frequency .workitem (which means autorelease each dispatch_async)
  • DispatchQueue.global has it set to .never (never autorelease automatically; it's up to you)
  • DispatchQueue.init creates one set to .inherit. By default, a new queue targets the global queue, which means it's implicitly .never.

documentation screenshot of .never

Note that this attribute only applies to .async(). If you do .sync(), you must always manually manage the autorelease situation.

docu screenshot of dispatch_sync

To answer your question: No. On main thread, you don't have to wrap your async block with autorelease{}. For any other queue, you either need to set the attribute or manually wrap in autorelease{}.

I recommend never dispatching directly to DispatchQueue.global if there's a risk something would be autoreleased, as that would either leak or end up in a never-emptied pool. Instead, create your own queues with explicit autorelease pool policy.

Why is @autoreleasepool still needed with ARC?

ARC doesn't get rid of retains, releases and autoreleases, it just adds in the required ones for you. So there are still calls to retain, there are still calls to release, there are still calls to autorelease and there are still auto release pools.

One of the other changes they made with the new Clang 3.0 compiler and ARC is that they replaced NSAutoReleasePool with the @autoreleasepool compiler directive. NSAutoReleasePool was always a bit of a special "object" anyway and they made it so that the syntax of using one is not confused with an object so that it's generally a bit more simple.

So basically, you need @autoreleasepool because there are still auto release pools to worry about. You just don't need to worry about adding in autorelease calls.

An example of using an auto release pool:

- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
@autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(@"number = %p", number);
}
}
}
}

A hugely contrived example, sure, but if you didn't have the @autoreleasepool inside the outer for-loop then you'd be releasing 100000000 objects later on rather than 10000 each time round the outer for-loop.

Update:
Also see this answer - https://stackoverflow.com/a/7950636/1068248 - for why @autoreleasepool is nothing to do with ARC.

Update:
I took a look into the internals of what's going on here and wrote it up on my blog. If you take a look there then you will see exactly what ARC is doing and how the new style @autoreleasepool and how it introduces a scope is used by the compiler to infer information about what retains, releases & autoreleases are required.

Autorelease pools and when release is called under iOS

Yes, UIKit does the same thing. The system-created, main thread autorelease pool is drained at the end of every run loop cycle. It's probably best not to rely on this exact lifetime in your own code. If you create a new thread manually (using e.g. NSThread), you're responsible for creating the autorelease pool on that thread.

EDIT: Rob's answer provides some good additional information regarding behavior under ARC. In general, it's fair to say that objects are less likely to end up in the autorelease pool due to some optimizations ARC is able to make.

Objective-C NSThread ref counting convention (retain vs autorelease)

Actually, performSelectorOnMainThread retains its arguments until after the selector is performed, so there's no need to do it.



Related Topics



Leave a reply



Submit