Reputation: 10167
I'm working through a somewhat tricky iPhone crash, and it looks like the culprit is an NSString being prematurely released. I've switched on NSZombiesEnabled and can see that the NSString is a zombie at the time of the crash. However, I can't determine when the object is being released/dealloced--I've combed through my code looking for release messages being sent to this object and have set breakpoints at these spots, but they're not being hit.
I assume this may be a threading or autorelease issue given it's intermittent nature, but is there any way to hook into the objective-c runtime via the Xcode debugger to tell the exact point where an object is being released? Or is there a better way to diagnose this issue?
Upvotes: 1
Views: 1230
Reputation: 1895
Another way to do this. Make sure to turn NSZombie on so it reports the memory address of the object that is getting the extra release. Then Run with Performance Tool->Object Allocations. This will bring up instruments. Look at the Console log as provided by Xcode organizer. Once you get the crash lookup the memory address in instruments. You will see the entire history of mallocs/frees on that object, as well as links straight into your code.
Upvotes: 2
Reputation: 1347
If you can reproduce the crash in the simulator, you may wish to look into using the malloc_history
tool. (It has a man-page.) You need to set some environment variables: I normally set them via the "Edit Active Executable" screen in the Arguments pane, and then use the check-boxes there to enable/disable them. Make sure you disable them before debugging on the device; if enabled the program will try to write to /tmp
which the sandbox doesn't allow.
I find this tool combined with NSZombie
lets me track down alloc/premature-release/access-after-dealloc errors. Once NSZombie
reports access to a deallocated object you can use malloc_history
to work out when the object was allocated. This normally sets me on the path to working out where the problem is.
Another tool I've found invaluable is clang from the LLVM project. It's still in development, but they regularly produce binaries for MacOS-X that seem pretty stable to me. In particular, it understands the Cocoa memory-management policy. Using it is as simple as:
% cd ${DIRECTORY_CONTAINING_XCODE_PROJECT}
% xcodebuild clean
% scan-build -V xcodebuild
This will do a full build of your project and produce a report listing any obvious errors (including reference-counting screw-ups) that the tool finds.
Upvotes: 5
Reputation: 5657
I might not be thinking straight, but have you considered adding a release and dealloc onto your class
- (void) release
{
NSLog(@"Releasing");
[super release];
}
- (void) dealloc
{
NSLog(@"Deallocating");
[super dealloc];
}
Incorporating Ben Gotow's comment to use an obj-c category, you end up with this:
@interface NSString (release)
-(void) release;
@end
@implementation NSString (release)
-(void) release
{
NSLog(@"NSString Released!");
[super release];
}
@end
Upvotes: 4
Reputation:
you could tell the objc
provider of dtrace
to trigger your probe whenever -[NSString release]
is called, but this will involve a little nasty hackery. NSStrings aren't actually NSStrings but are all subclasses, because of the way the class is implemented as a class cluster. Now, that's not going to get in our way; what will is that NSString
doesn't have its own -release
:-). You can provide your own in a category, though.
Alternatively, if it's easy for you to tell which instance of NSString
is going to break, you could just set a conditional breakpoint on -[NSObject dealloc]
with self==myInstance
.
Upvotes: 2
Reputation: 60508
Could you implement dealloc() and put a breakpoint in there? Looking at the stack trace from that point should tell you where and how it's being released.
Upvotes: 0