Inconsistent crash due to "message sent to deallocated instance" in iPhone App
Originally, my application was crashing do to BAD_EXEC_ACCESS. I turned on NSZombieEnabled, that output is below. The crashing is extremely inconsistent, If it crashes, it always crashes in one of three places, but it doesn't always crash when passing over those lines of code. I.e. sometimes it crashes at one of those places within the first 10 user interactions, and sometimes I can keep pressing controls (with it passing through those lines of code) for over a minute before it finally crashes.
The output of NSZombieEnabled is also inconsistent, as noted in "Crash Location #2" -- the two NSZombieEnabled outputs are examples of the application crashing on the same line of code, but with different NSZombieEnabled output.
I know that generally this type of error means I am over releasing something, but I can't figure out any more specifically than that what I am doing wrong.
The memory management rules I'm following are:
- For every init/alloc I have a corresponding release (At no point in my code is this more complicated than an object being created in a method and then being release later in the same method).
- For every property that is retained, I have a corresponding release in dealloc()
(I have heard about "setting IBOutlets to nil开发者_运维问答" as related to memory management, but I have not found an adequate description of how this is done, so this is not done in my app.)
Please let me know if there is any additional information I could provide that would be helpful.
Thanks in advance! Sorry if I am too long and thorough (INTP)!
-Roben
Below is a record of some output from the crashes. When a crash occurs, it is always in one of these three locations. The locations were determined by doing a backtrace after the crash and looking for line numbers and files of code that I wrote.
Crash Location #1:
if (![[self fetchedResultsController] performFetch:&error])
Example Crash Location #1 NSZombieEnabled Output:
*** -[Not A Type release]: message sent to deallocated instance 0x3b3f570
Crash Location #2:
NSMutableArray *tips = [NSMutableArray arrayWithArray: [[[categories objectAtIndex: indexPath.row] valueForKey:@"tips"] allObjects]];
Example Crash Location #2 NSZombieEnabled Output:
*** -[CFArray retain]: message sent to deallocated instance 0x3e53990
*** -[NSFetchRequest retain]: message sent to deallocated instance 0x3b2f2c0
Crash Location #3:
NSMutableArray *tips = [NSMutableArray arrayWithArray: [[[justOneCategory objectAtIndex: 0] valueForKey:@"tips"] allObjects]];
Example Crash Location #3 NSZombieEnabled Output:
*** -[UIViewControllerWrapperView retain]: message sent to deallocated instance 0x3e593a0
Example Backtrace (this corresponds to Line #3):
#0 0x01d6a3a7 in ___forwarding___ ()
#1 0x01d466c2 in __forwarding_prep_0___ ()
#2 0x01cfd988 in CFRetain ()
#3 0x01cfd495 in CFArrayCreate ()
#4 0x01d406c3 in -[__NSPlaceholderArray initWithObjects:count:] ()
#5 0x01d5d34a in +[NSArray arrayWithObjects:count:] ()
#6 0x01d6386e in -[NSSet allObjects] ()
#7 0x00003bbc in -[RootViewController getRandomTip:] (self=0x3b24ea0, _cmd=0x7447, sender=0x3b38330) at /Users/***/Classes/RootViewController.m:36
#8 0x00299405 in -[UIApplication sendAction:to:from:forEvent:] ()
#9 0x002fcb4e in -[UIControl sendAction:to:forEvent:] ()
#10 0x002fed6f in -[UIControl(Internal) _sendActionsForEvents:withEvent:] ()
#11 0x002fdabb in -[UIControl touchesEnded:withEvent:] ()
#12 0x002b2ddf in -[UIWindow _sendTouchesForEvent:] ()
#13 0x0029c7c8 in -[UIApplication sendEvent:] ()
#14 0x002a3061 in _UIApplicationHandleEvent ()
#15 0x0252ed59 in PurpleEventCallback ()
#16 0x01d41b80 in CFRunLoopRunSpecific ()
#17 0x01d40c48 in CFRunLoopRunInMode ()
#18 0x0252d615 in GSEventRunModal ()
#19 0x0252d6da in GSEventRun ()
#20 0x002a3faf in UIApplicationMain ()
#21 0x00002a60 in main (argc=1, argv=0xbfffef9c) at /Users/***/main.m:14
EDIT: Adding Some additional code and output requested by Griffo
Thanks for the response, re more code anything in specific that would be helpful? For now here is the entirety of the method that contains both Crash Location #1 and Crash Location #2.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == ALLTIPS_SECTION) {
self.tipsController.title = @"Tips";
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
// NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
// abort();
}
self.tipsController.tips = [NSArray arrayWithArray: [fetchedResultsController fetchedObjects]];
} else {
self.tipsController.title = [[categories objectAtIndex: indexPath.row] name];
NSMutableArray *tips = [NSMutableArray arrayWithArray: [[[categories objectAtIndex: indexPath.row] valueForKey:@"tips"] allObjects]];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending: YES];
[tips sortUsingDescriptors: [NSArray arrayWithObject: sortDescriptor]];
[sortDescriptor release];
self.tipsController.tips = [NSArray arrayWithArray: tips];
}
[self.navigationController pushViewController:self.tipsController animated:YES];
}
I did not run malloc_history on the specific crash you asked about, but I did run it on #3, here that output, I have no idea how I am supposed to parse this, so any advice would be helpful (in all the tutorials on malloc_history I've read they show the output and they're all like "there it is" and I'm like "where? wtf are you looking at"):
ALLOC 0x3b55130-0x3b5516f [size=64]: thread_a0a3f500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | PurpleEventCallback | _UIApplicationHandleEvent | -[UIApplication sendEvent:] | -[UIWindow _sendTouchesForEvent:] | -[UIControl touchesEnded:withEvent:] | -[UIControl(Internal) _sendActionsForEvents:withEvent:] | -[UIControl sendAction:to:forEvent:] | -[UIApplication sendAction:to:from:forEvent:] | -[RootViewController getRandomTip:] | -[_NSFaultingMutableSet allObjects] | -[_NSFaultingMutableSet willRead] | -[NSManagedObjectContext(_NSInternalAdditions) _retainedObjectWithID:optionalHandler:withInlineStorage:] | +[NSManagedObject(_PFDynamicAccessorsAndPropertySupport) allocWithEntity:] | _PFAllocateObject | malloc_zone_calloc
----
FREE 0x3b55130-0x3b5516f [size=64]: thread_a0a3f500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | _performRunLoopAction | -[_PFManagedObjectReferenceQueue _processReferenceQueue:] | _PFDeallocateObject | malloc_zone_free
ALLOC 0x3b55130-0x3b55153 [size=36]: thread_a0a3f500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CALayerLayoutIfNeeded | -[CALayer layoutSublayers] | -[UILayoutContainerView layoutSubviews] | -[UINavigationController _startDeferredTransitionIfNeeded] | -[UINavigationController _startTransition:fromViewController:toViewController:] | +[UIViewControllerWrapperView wrapperViewForView:frame:] | +[NSObject alloc] | +[NSObject allocWithZone:] | _internal_class_createInstance | _internal_class_createInstanceFromZone | calloc | malloc_zone_calloc
Several things to look at:
First, regarding "setting to nil," this is a good practice. Any time you release something, immediately set it to nil. This means that -dealloc often looks like this (or a dozen other styles with semi-colon, two lines, etc.):
[_foo release], _foo = nil;
But I doubt this is your problem. In the malloc_history you sent, it shows that the object in question is an NSManagedObject, so it's something out of Core Data. Make sure you've read the Memory Management Using Core Data docs.
If you have 10.6, then I highly recommend the static analyzer. Hit Cmd-Shift-A and it'll look for obvious memory errors. I've found it's quite good at it.
Possibly due to you autoreleasing an object which you later reference, that might explain the inconsistency
"Not a type" release error might be down to you releasing something which is not defined as 'something' in the code. Did you run the 'shell malloc history' command for the deallocated instance referenced by the "not a type" error?
Need to see more code really...
That is where the crash occurs, but that doesn't mean it's where the bug lies. The crash occurs because a deallocated object is being sent a message, but the bug is probably the fact that the object was deallocated in the first place when you still want to use it. I have a vague feeling the initial deallocated object might be tipsController
or fetchedResultsController
and it's releasing the other stuff as well.
I had this error. I had copied and pasted code from another app, that worked slightly differently. In my case, I was releasing variables in viewDidUnload & viewWillDisappear. I commented out the viewWillDisappear releases, left the ones in the viewDidUnload and the app worked fine without crashing. Hope this helps someone else.
精彩评论