Find your Garbage Collection leaks with Instruments

While making JSCocoa play nice with the ObjC garbage collection I've had trouble fixing the leaks. JSCocoa is a bit peculiar because it must protect and unprotect Javascript values from the Javascript GC, but mark them as reclaimable as objects die. Plus there's some malloc and mmap memory that must be freed manually.

Instruments usually works great for finding leaks, but alas doesn't work under ObjC's garbage collection. We can however find a reasonable substitute in the ObjectAlloc instrument by approaching the problem differently :

  • Display only Created and Still Living objects in ObjectAlloc
  • Switch to Diagram View, listing all instances
  • Open the call stack (Its button is just on the right of Diagram View)
  • Run a piece of code multiple times and see which objects pile up :)

Run Instruments with Run→Start with Performance Tool→Object Allocations. After that, each Build and Go will launch the new build in Instruments. Image:Find your garbage collection leaks in instruments.png

From there we can filter objects by responsability, that is showing only the objects from our app or from a specific lib. That was particularly useful to find both my leaks and a leak from my JavascriptCore usage. JSStringCopyCFString will create CFStrings that I usually cast to NSString then release — but this leaks as CFTypes must be CFReleased. Instruments pinpointed each instance of the problem. I could then double click the function call in the call stack, open the leaky code in XCode and fix it on the spot.

What changed in JSCocoa to enable it for GC :

  • Finalize Added a finalize method to do the cleanup usually done in dealloc
  • NSMakeCollectable Tagged autoreleased CFStrings with NSMakeCollectable. A function like JSStringCopyCFString returns a CFString and it must be released as such — release and autorelease will leak. The recommended Apple way to handle both GC and non-GC code is [NSMakeCollectable(myCFString) autorelease]
  • malloc_autorelease usage is gone :( malloc_autorelease delegated the responsability to free memory to an autoreleased NSData instance. The ObjC collector collected the NSData early thus trashing the memory used downstream !
  • disable allocation for specific pointers After loading a BridgeSupport file, an adhoc parser gets a char * pointer to [loadedDocument UTF8string]. The parser then advances the pointer to parse, changing it from its original value. Not finding a reference to the original pointer, the GC collects live memory. disableCollectorForPointer and enableCollectorForPointer will protect/unprotect that pointer as long as you want.

Some Garbage Collection Resources

Follow me on Twitter
Planet Cocoa

2011 02 22Distance field
2010 07 202Binding through NSApp
2010 05 122Forwarding invocations
2010 02 272Core Image black fringes
2010 02 21Quickest Way to Shell
2010 02 08Who's calling ?
2009 09 2138 ways to use Blocks in Snow Leopard
2009 08 182Bracket Mess
2009 08 124Taming JavascriptCore within and without WebView
2009 04 15Debugging with Activity Monitor
2009 03 25How Core Image Color Tracking works
2009 03 1510Custom NSThemeFrame
2009 03 10Which framework is running ?
2009 03 074CoreUI can paint pretty big
2009 02 18Localization with functions
2009 01 30Did you forget to nest alloc and init?
2009 01 16JSCocoa on the iPhone
2009 01 11Mixing WebView and JavascriptCore
2009 01 09Badge overflow
2009 01 09Find your Garbage Collection leaks with Instruments

Powered by MediaWiki