RubyMotion now uses LLDB for debugging. Previously it
If you’re getting random crashes with little or no backtrace it may be down to
a memory allocation issue.
Launch your application with the debugger running via:
$ rake debug=1 NSZombieEnabled=YES MallocStackLogging=1
Trigger your bug and you should get output in Terminal like this:
2013-10-16 10:17:19.594 YourAppName[68253:a0b] *** -[UIBarButtonItem isSystemItem]: message sent to deallocated instance 0x9fd56f0
Process 68253 stopped
* thread #1: tid = 0x3127cd, 0x03ac0811 CoreFoundation`___forwarding___ + 769, queue = 'com.apple.main-thread, stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
frame #0: 0x03ac0811 CoreFoundation`___forwarding___ + 769
CoreFoundation`___forwarding___ + 769:
-> 0x3ac0811: jmp 0x3ac090c ; ___forwarding___ + 1020
0x3ac0816: movl %edi, (%esp)
0x3ac0819: calll 0x3bb840e ; symbol stub for: class_getSuperclass
0x3ac081e: movl %eax, %edi
Leave your application running and open a separate tab in Terminal. You can
malloc_history of the object that has been deallocated via:
/usr/bin/malloc_history 68253 0x9fd56f0
Note the first argument is the Process ID as indicated where it says
Process 68253 stopped. Note that the Ruby process that performs the build and
launches your app (i.e. rake) is not the same as your app process.
The last argument is the Object Reference as indicated by
message sent to deallocated instance 0x9fd56f0.
This (hex) number is the address of a piece of memory where the object we are
interested in (was) located. The other traces in the malloc history are cases
where that same memory location was used.
Running the above command will give you a dump of information from the stack logs.
I’ve truncated the following example, as the information is plentiful, but it
shows the kind of output you can expect:
malloc_history Report Version: 2.0
Process: YourAppName 
Load Address: 0x1000
Version: ??? (???)
Code Type: X86 (Native)
Parent Process: debugserver 
Date/Time: 2013-10-16 11:14:24.104 +0100
OS Version: Mac OS X 10.8.5 (12F45)
Report Version: 7
ALLOC 0x9fd56f0-0xa64da98 [size=425]: thread_4925a28 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | ...
FREE 0x9fd56f0-0xa64da98 [size=425]: thread_4925a28 |start | main | UIApplicationMain | -[UIApplication _run] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSource1 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ | PurpleEventCallback | _PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | ...
ALLOC 0x9fd56f0-0xa64dacf [size=112]: thread_4925a28 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | ... | rb_scope__initWithFillColor:__ | vm_dispatch | rb_vm_dispatch | builtin_ostub1(objc_object* (*)(objc_object*, objc_selector*, ...), objc_selector*, objc_object*, unsigned char, int, unsigned long*) | _objc_rootAlloc | class_createInstance | calloc | malloc_zone_calloc
The output shows there had been two mallocs in the life span of the app and only
one was freed.
If I was not expecting the first ALLOC to be freed, then I would investigate the
trace of the FREE to figure out why it was freed. Alternatively if I was expecting
the second ALLOC to be FREEd as well, then I would know that did not happen.
I knew I was expecting the memory to be freed and it was towards the end of the
second ALLOC block I could see my own method
initWithFillColor being called.
I was subclassing
UIBarButtonItem with my method
initWithFillColor like so:
class MenuButton < UIBarButtonItem
UIMenuButtonIcon.alloc.initWithFrame(CGRectMake(0.0, 0.0, 25, 15), fillColor:fillColor).tap do |button|
button.addTarget(self, action:"showMenu", forControlEvents:UIControlEventTouchUpInside)
initWithFillColor method obviously doesn’t need to create another instance
UIBarButtonItem. So I updated it to the following and my memory bug was gone:
Hopefully this is a good start for debugging any memory bugs in your RubyMotion
Thanks to the latest HipByte employee, Eloy Durán, for the tips!