0

My day was ruined by this message:

*** -[CALayer retainCount]: message sent to deallocated instance 0x656b260

Since I don't create CALayer myself in this case, it can only be the CALayer of a UIView which might be anything from a UIButton to a UISlider.

So I got a great answer from Jeff to my question about how to trace this down in Xcode 4.

Jeff recommended hitting Command + I to launch the Profiler and then select the Zombies instrument. Indeed, the Zombies instrument stopped on that CALayer and threw a more useful stack trace at me.

However, the Stack Trace isn't that useful as it does not tell me which object that Zombie really was. Every UIView has a CALayer, but the point is I don't create these CALayer instances myself. So in this case the goal is to know to which UIView (button, slider, whatever) that CALayer belongs to.

   0 libSystem.B.dylib calloc
   1 libobjc.A.dylib class_createInstanceXcode4
   2 CoreFoundation +[NSObject(NSObject) allocWithZone:]
   3 CoreFoundation +[NSObject(NSObject) alloc]
   4 UIKit -[UIView _createLayerWithFrame:]
   5 UIKit UIViewCommonInitWithFrame
   6 UIKit -[UIView initWithFrame:]
   7 UIKit -[UIControl initWithFrame:]
   8 UIKit -[UIButton initWithFrame:]
   9 UIKit +[UIButton buttonWithType:]
  10 TestApp +[CCButton buttonWithNormalImage:pressedImageName:] /Users/tom/Documents/testcomp/Projects/TestApp/Xcode4/Classes/CCButton.m:267
  11 TestApp -[ConfigView setupCommitBlade] /Users/tom/Documents/testcomp/Projects/TestApp/Xcode4/Classes/ConfigView.m:606
  12 TestApp -[ConfigView initWithRootVC:] /Users/tom/Documents/testcomp/Projects/TestApp/Xcode4/Classes/ConfigView.m:714
  13 TestApp -[TestAppViewController loadConfigViewIfNeeded] /Users/tom/Documents/testcomp/Projects/TestApp/Xcode4/Classes/TestAppViewController.m:69
  14 TestApp -[TestAppViewController viewDidLoad] /Users/tom/Documents/testcomp/Projects/TestApp/Xcode4/Classes/TestAppViewController.m:293
  15 UIKit -[UIViewController view]
  16 TestApp -[TestAppAppDelegate application:didFinishLaunchingWithOptions:] /Users/tom/Documents/testcomp/Projects/TestApp/Xcode4/Classes/TestAppAppDelegate.m:238
  17 UIKit -[UIApplication _callInitializationDelegatesForURL:payload:suspended:]
  18 UIKit -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:]
  19 UIKit -[UIApplication handleEvent:withNewEvent:]
  20 UIKit -[UIApplication sendEvent:]
  21 UIKit _UIApplicationHandleEvent
  22 GraphicsServices PurpleEventCallback
  23 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
  24 CoreFoundation __CFRunLoopDoSource1
  25 CoreFoundation __CFRunLoopRun
  26 CoreFoundation CFRunLoopRunSpecific
  27 CoreFoundation CFRunLoopRunInMode
  28 UIKit -[UIApplication _run]
  29 UIKit UIApplicationMain
  30 TestApp main /Users/tom/Documents/testcomp/Projects/TestApp/Xcode4/main.m:14
  31 TestApp start

Maybe someone can point out a tutorial or video which shows how to profile a problem like this in Xcode4? As far as I remember, Xcode 3 really pointed out which object it was, but here I just don't see where the evil is. There must be some rule of thumb how to interpret this stack trace correctly / or a good reason why the Zombies instrument doesn't simply point out the line of code where the zombie appeared.

Community
  • 1
  • 1
dontWatchMyProfile
  • 45,440
  • 50
  • 177
  • 260

1 Answers1

1

You need to turn on malloc stack logging in the Edit Scheme > Diagnostics panel. Then, when you get the zombie error, you can do this in the gdb console:

info malloc-history -exact 0x656b260

Use the address from the zombie message, of course. It may be different on each run.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Great! But I think I'm not using GDB. Isn't Xcode 4 based on LLVM now? – dontWatchMyProfile Nov 29 '11 at 00:02
  • You can still use GDB in Xcode, regardless of which compiler you use. – rob mayoff Nov 29 '11 at 00:04
  • So the Zombies instrument doesn't turn this flag on automatically? – dontWatchMyProfile Nov 29 '11 at 00:06
  • You need to turn on zombies in Xcode and run the app in Xcode. You can turn on Zombies in the same panel that you turn on malloc stack logging. – rob mayoff Nov 29 '11 at 00:07
  • Thanks! But there's the Zombies instrument - so the Zombies instrument (CMD + I) does not turn anything on in order to work properly? That's what I would actually expect. – dontWatchMyProfile Nov 29 '11 at 00:09
  • You can get to the debug console by choosing View > Debug Area > Activate Console. Whenever your program is paused, you can run gdb commands. It should pause automatically after a zombie message. If you want to pause it manually, you can choose Product > Debug > Pause. – rob mayoff Nov 29 '11 at 00:11
  • Great! Thanks! I figured the gdb prompt only comes after a crash. Looked for it before it happened. My bad. – dontWatchMyProfile Nov 29 '11 at 00:13
  • Great info so far, but I don't see how this is any different than what the Zombies instrument throws at me. Basically the same stack trace and same problem. Doing it manually in GDB is even harder as it won't colorize anything. – dontWatchMyProfile Nov 29 '11 at 00:17
  • You should get a stack trace for when malloc and free were called on the zombie object. The stack trace for the malloc should give you a hint as to what UIView owned the layer. – rob mayoff Nov 29 '11 at 00:24
  • Apparently you can look at the malloc stack history in Instruments. Read this: http://www.markj.net/iphone-memory-debug-nszombie/ – rob mayoff Nov 29 '11 at 00:25