How to tell when object is sent release message? - iphone

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?

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.

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

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.

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.

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.

Related

app runs fine with debug build, but crash on release build, what could be the possible reasons?

I have Xcode 4.3.1, iOS 5.1, and have ARC turned on for building my app.
Now the app runs fine in debug build, but crash on release build. What could be the possible reason for the difference? I purely rely on ARC for the resource management. I looked at the crash log, it's indicating that the memory that was referencing was released already. What'll be the common pitfalls that could cause the problem on retail build, when using ARC?
The following is what I got from crash log
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x6f636552
Crashed Thread: 0
EDIT
The app's deployment target is iOS 5.0. I do use internet connections, the current crash happens on the time when "rendering" the data returned from web service in order to show on a UITableViewController. The whole app is using ARC, except a few source files from 3rd party for which I have ARC turned off.
Whenever this happens to me it seems to be because release builds are more aggressive about clearing up weak references. If you mistakenly assign something to a weak property (for example, if you're adding subviews that you will also hold weak references to) before you have any strong reference to it, this can work on debug and fail on release. For example (pseudocode)
#property (weak) UILabel * label;
...
self.label = [[UILabel alloc] init];
[self.view addSubview:self.label];
...
self.label.text = #"hello";
I've seen this cause bad access crashes on release builds and go unnoticed on debug.
I may not have the answer but I'm going to list a few hunches for you to try:
Make sure you are not passing objects into methods without a "handle" on it on your side. And example would be passing a handler class instance to a method that expects a delegate. The method doesn't retain that instance and so it gets released before it even calls the method.
Check your pre-compiler macros that they are safe for both DEBUG & RELEASE builds. A good example is having an if statement over a macro that is removed in release builds and the if statement doesn't cover it with curly braces.
If you depend on compiler definitions to enable/disable certain parts of your code (through the use of #if conditions) make sure the needed ones are set in your build configuration.
If I can think of more, I'll try to add them.
Do you have a different target for release and debug? Check whether all the files are correctly referenced for the release target.
In our case, a category on UIButton was not seen by the release target. An ad-Hoc build went just fine, until someone invoked a method implemented by that category. Since we did not store an archive from the Ad-Hoc build, there was no way to debug a crash. (lesson learned)
Not sure whether it is listed as EXC_BAD_ACCESS in a crash log, but could help someone to identify their release-specific crash.

Releasing Autoreleasepool crashes on iOS 4.0 (and on 4.1 as well..)

I'm wondering what could cause this.
I have several methods in my code that i call using performSelectorInBackground.
Within each of these methods i have an Autoreleasepool that is being alloced/initialized at the beginning and released at the end of the method.
this perfectly works on iOS 3.1.3 / 3.2 / 4.2 / 4.2.1 but it fataly crashes on iOS 4.0 with a EXC_BAD_ACCESS Exception that happens after calling [myPool release].
After I noticed this strange behaviour I was thinking about rewriting portions of my code and to make my app "less parallel" in case that the client os is 4.0.
After I did that, the next point where the app crashed was within the ReachabilityCallback-Method from Apples Reachability "Framework".
well, now I'm not quite sure what to do.
The things i do within my threaded methods is pretty simple xml parsing (no cocoa calls or stuff that would affect the UI). After each method finishes it posts a notification which the coordinating-thread listens to and once all the parallelized methods have finished, the coordinating thread calls viewcontrollers etc...
I have absolutely no clue what could cause this weird behaviour. Especially because Apples Code fails as well.
any help is greatly appreciated!
thanks,
sam
The best way to detect zombies is:
in the Groups and Files section, expand the Executables section and right click on your app name and choose Get Info
select the Arguments tab on the top and then add a new entry in the Variables to be set in the environment section. Name the new variable to NSZombieEnabled and set its value to YES.
After this you will have information in console on which released objects you make calls.
Seem's like i've solved the Issue.
The Problem was, that (as many of you suggested) I've overreleased an NSURL Object within a Method which calls [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&error];
I assume that stringWithContentsOfURL autoreleases the NSURL object that i pass as a parameter.
after removing the release on urlRequest the issue dissapeared. Still i think that it's very strange that different iOS Versions behave differently on that matter.
the whole method looked like this:
-(NSString*)downloadContent:(NSURL*)urlRequest
{
NSString *data = nil;
NSError *error = nil;
data = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&error];
//[urlRequest release]; //Crashes on iOS 4.0 / 4.1 later when autoreleasepool is being released.
return data;
}
Sounds like an autoreleased object created in the scope of that autorelease pool is being released somewhere it shouldn't be. Not sure why the behaviour differs with the version of the SDK; there must be an implementation difference somewhere that's causing the issue. Have you built the code using "Build and Analyze"? Does it suggest anything might be over-released?
I've noticed some strange behavior with performSelectorInBackground also. I might be completely wrong on this, but in my case I've used:
[NSThread detachNewThreadSelector:#selector(blah) toTarget:self withObject:nil];
with better results. If, when you're in that method, you need to access the main thread (to update the UI for example), you can just:
[self performSelectorOnMainThread:#selector(blah2) withObject:nil waitUntilDone:false];

Is it possible to set up XCode to do the reference counting for me?

I'd like to know if is it possible to set up Xcode to do the reference counting and show warnings if number of "retain" and "release" are not matching?
Use the Build > Build and Analyze command, or cmd-shift-A. The static analyzer can catch a lot of mistakes in that area.
That's what the Instruments tools are for.
For more retains than releases:
Leaks will tell you when you no longer have a reference to an object, but it still has retains.
Object Alloc will show you all the objects still retained in the system at any point in time. Don't forget that many things should not be released, until your program ends... so it's impossible for the system to know when you have too many retains, except for the Leaks case. Object alloc can also show you, for any object, the complete history of retain and release calls.
If you have more releases than retains, you will know pretty much instantly because the application will crash. In that case, you turn on "NSZombieEnabled" by selecting your executable, "Get Info", and then in the General tab enter the environment variable "NSZombieEnabled" to "YES". Then when you try to access an object you have released you'll see an error message in the log. It can also help a lot to run Object Alloc, and tell it to pay attention to Zombies. Don't leave on the zombie detection though, as it works by never ever releasing memory.

What's the best way to fix memory leaks on the iPhone?

I'm trying to use XCode's Leaks utility to fix some memory leaks in my code. Is there a better and more understandable way to check for leaks with explanations that pinpoint the exact line and/or offer suggestions?
Another question, I'm using AVAudioRecorder in my code in one of my view controllers. Should I load the recorder in viewDidLoad or in viewWillAppear?
If you're using Snow Leopard, have you tried using the static analyzer?
As mentioned, use Static Analyzer as a first line of defense.
It will not find everything.
But here's the problem with what you are requesting of Leaks. Think about what a leak is - a leak is when you have memory, that should have been released, but it is not.
So that means you are MISSING a line of code, that could have been placed anywhere - doing the actual release at the right time. But how could the tool possibly know when something SHOULD have been released?
So instead, the tool does the next best thing. It tells you where the leaking memory was allocated, then from there it's up to you to figure out where the object travelled and when it should actually have been released.
Static Analyzer will find the cases where you should have released in a few lines of code from when you created the object. Anything else, you just need to use Leaks to get a starting point to track down when you need to release something elsewhere.

iphone debugging help- see when objects are released?

I'm a little ways into developing my first iphone app, and I've been running into exc_bad_access a lot. (I'm sure it's because I'm not designing stuff in a very MVC-proper way yet.)
It's extremely frustrating trying to hunt down why I'm running into these errors all the time... is there a way in the xcode debugger to keep a watch list of pointers, so you can actually see when various objects are being released? Something, anything that can give me more of a visual understanding of why my program design is flawed?
In particular, I keep having trouble with my "webobject" class I've wrapped all of my NSURLConnection methods in. When I try to call performselector to the view controller that initiated a "webobject" request, I keep getting exc_bad_access when I try to access the webobject's synthesized properties. Is there something fundamentally wrong with my notion that I should wrap all of my webservice-related methods into a class that I can import anywhere?
Dave,
I don't know of a way to trace the deallocation of objects (especially native objects like NSStrings). But, I experienced a similar abundance of exc_bad_access messages when starting Objective-C programming. But one day I read something that helped me alot to get rid of these messages:
If you create an object using alloc, copy, or a method that begins with new, then it is your object to manage and dealloc. You can call retain and release and that cycle will work as expected on those objects. If you never call release or dealloc on it, it will hang around foreever and be a leak. If you call a method that is something like 'stringWithFormat', numberWithYadaYada then that object is set for autorelease. Meaning, as soon as you exit the method that is using it, it may get dealloced. Therefore, if you've called one of these autorelease methods, you must retain it if you want to see it later on.
I suspect that either your delegate or NSURLConnection is getting autoreleased, that is the cause of your bad access messages.
Jack
You could try creating a breakpoint on -[NSObject dealloc] (or the same method on the subclass you are targetting).
I would also refer you to one of the many Cocoa memory handling tutorials.
I ended up reading up about NSZombieEnabled, which has helped me track down those exc_bad_access messages. More info here: http://www.cocoadev.com/index.pl?NSZombieEnabled
Just as a general thing, you should run as a static analyzer and it will probably tell you when you are over or under retaining objects.
pertinent stackoverflow question