Why My Next Mac App Will Not Use Garbage Collection

Among the many things I have learned from the past few years' experience of developing desktop applications, here's one: Implement your app conservatively. This often translates to using only proven technologies. Cocoa's garbage collection (gc), alas, does not seem to be one of them. My next Mac app will not use garbage collection. In fact, we are actually even taking the pain of modifying an existing garbage collected app to non-gc.

Since Mac OS X 10.5, you can choose to use automatic garbage collection in your Cocoa app. Apple's take on gc is a brilliant engineering feat, which makes Objective-C a more modern language (and it's even open source). Before gc, memory management is much like manual transmission and requires a lot of mental arithmetic — you need to retain an object (to increase its refcount) when you start using it, and release it (to decrease its refcount) when you relinquish its ownership. With gc, no more such mental arithmetic is required. It's great that you are saved the burden of memory management, particularly when you have other more nasty things to worry about, such as multithreading (which makes manual management harder) and binding (which complicates object graph).

Unfortunately, I have found a few instances that Cocoa's gc doesn't work that well. This has particularly to do with libraries that are beyond gc's reach. I'll name three: Secure Transport (which handles things like HTTPS), icucore (which handles localization and date/time formatting), and XML parsers (I have tried both NSXMLParser and expat). These three can already leak from time to time when being called from the main thread alone, and almost gurantee to leak if used in different threads, even if proper locks and one-instance-per-thread-at-a-time policies are enforced.

You might be tempted to think, big deal, if those stacks have their baggage and work best in a non-gc app, I'll just write a separate app, and use distributed objects (DO), another fancy technology, to bridge between the gc and non-gc processes. Here's the bad news: There is apparently a bug in Apple's DO implementation under gc, and all proxies objects that ever created to communicate with the remote process will not be destroyed until the app's termination.

So for the time being my conclusion is, if your app is network-intesive, needs to do a lot of things in parallel, and happens to parse a lot of XML and has a fairly complex user interface that relies on binding, then garbage collection probably isn't for you.

Now the only big question that I have is, how did Xcode manage it? Xcode, as we know it, is a garbage collected app1. It's also said to be Apple's most complicated application. Now, unlike, Xcode doesn't seem to do lots of date/time formatting. It reads plist (for which Apple has a faster parser implemetation) but not really XML. The only network-bound parts seem to be the documentation fetcher and the recently-added automatic iPhone provisioning. Much of the IDE seems to be there already in OS X 10.3 days. All told, Xcode seems to stand well.

I'd like to know to make those non-Cocoa parts work with gc. But before that, I'll take the more conservative path.

  1. I know this because the previous generation of our Adobe Kuler color picker, Mondrianum, used (and still uses) a cover flow image view, which doesn't work under gc. In the previous generation, we used some NSGarbageCollector hacks (don't ask) to manage to make the plug-in work within Xcode. In the current version we have decided not to support gc apps like Xcode, because those hacks never worked perfectly.