Why isn’t my autoreleased object getting released?
I am debugging a weird memory management error and I can’t figure it out. I noticed that some of my objects are staying in memory longer than expected. I checked all my memory management and finally got to the very improbable conclusion that some of my autorelease
operations don’t result in a release
. Under what circumstances is that possible? I created a small testing Canary
class that logs a message in dealloc
and have the following testing code in place:
NSLog(@"On the main thread: %i.", [NSThread isMainThread]);
[[[Canary alloc] init] autorelease];
According to the code we’re really on the main thread, but the dealloc
in Canary
does not get called until much later. The delay is not deterministic a开发者_高级运维nd can easily take seconds or more. How is that possible? The application runs on a Mac, the garbage collection is turned off (Objective-C Garbage Collection is set to Unsupported on the target.) I am mostly used to iOS, is memory management on OS X different in some important way?
The only circumstance in which autorelease
does not behave as expected is when there is no autorelease pool on the current thread. There are only a few situations where you can expect this to occur, and if it does, you get a very loud log message printed to the console. If you're not seeing that log, then autorelease
is behaving appropriately. Far more likely is the fact that something on your code is calling retain
on this Canary object and then never releasing it.
Autoreleased objects do not get released until their pool is drained. So, if you are looping through images with an autoreleased buffer, it would be good to create and drain a pool every time through the loop.
There’s a blog post by Mike Ash called More Fun With Autorelease that explains the source of this problem. Quote:
As everybody knows, every time you go through the event loop, Cocoa blows away the old pool and makes a new one for you, so that all of your autoreleased objects go away and your new ones go into a fresh pool. That way you never build up more objects than get produced during a single event loop cycle. The key word is “event loop”. In Apple's infinite wisdom, things that aren't real actual NSEvents don't trigger the pool.
I'm currently working on an app that spends a lot of time in the background doing dark, unspeakable things with NSStreams on the main thread. I encountered a bug where one of my objects can get destroyed in the middle of handling a stream event, which left it open to getting other stream events after it was deallocated. (…)
The obvious fix was to simply do
[[self retain] autorelease]
before making the problem call. And fix it it did, except instead of my dealloc happening in the middle of my event handler, it never happened at all.Until I clicked on my app’s dock icon.
At least the solution was easy. Post an
NSApplicationDefined
event in the stream event handler, and autoreleased objects get destroyed on schedule.
I swear I have to read the blog from cover to cover, it’s a good time investment.
精彩评论