开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜