I've seen suggestions saying to set NSZombieEnabled to true while debugging. What is NSZombie? Is it a framework? A setting?
It's a memory debugging aid. Specifically, when you set NSZombieEnabled then whenever an object reaches retain count 0, rather than being deallocated it morphs itself into an NSZombie instance. Whenever such a zombie receives a message, it logs a warning rather than crashing or behaving in an unpredictable way. As such, you can debug subtle over-release/autorelease problems without advanced tools or painstaking needle in haystack searches.
The name is a fairly obvious play on the fact that objects are normally considered "dead" when they reach retain count 0. With this setting, they continue to exist in a strange half-life - neither living, nor quite dead. Much like real zombies, except they eat rather fewer brains.
Adam did a great job explaining what Zombies are, but using the environment variable is not the best way to find and track these.
A much better approach to zombie detection, is just to use Instruments - from XCode start with "Run with Instrument" and choose "Allocations".
Then stop the recording right after it starts, press the "i" button on the Allocations instrument, and turn on "enable reference counts" and "Enable NSZombie Detection". Now hit Record again in the instrument, and your app will start up - if any zombie objects are sent messages recording will stop, and a dialog box will pop up in the recording timeline - you can click on that to find every place an object was retained or released.
Edit: Previous advice was for XCode 3, here's an addition for XCode 4:
In XCode 4.2, there's an even easier mechanism to make use of Zombie detection - the Zombie Instrument. Instead of "Run" to start the app, use "Profile" and an instrument selector will come up. Select "Zombie", and the app will start running - do whatever causes your crash, an a dialog will pop up saying "Zombie Messaged".
From there, click the small arrow in the dialog box. That will take to a list of all the times that zombie object was created, retained, or released. Pull up the side bar and you can go to each entry, looking at the stack trace for the code that was responsible for each adjustment in the retain count.
I agree with what Kendall added, it's very useful, but I'll suggest still doing the environment variable so you don't forget they're enabled. Similar to the (now expired) link at Cocoa Dev, I put this so I don't miss it:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled")) {
NSLog(#"ZOMBIES/AFOC ARE ENABLED!!! AAAAARRRRRRGH!!! BRAINS!!!");
}
It catches my attention very nicely.
Would help someone.
Detailed document on Instruments.
https://developer.apple.com/library/watchos/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/index.html#//apple_ref/doc/uid/TP40004652-CH3-SW1
Related
I am facing this weird random crash where I get EXC_BAD_ACCESS on an object that exists. I am totally stumped on why this is happening. The code in the image executes without any issues 99.99% of the time. I saw this crash second time and that when I thought I should figure out what might be going wrong. I am executing this code on the main thread and the crash line has two core data objects. This shouldn't be a concurrency issue because it's only used in this class. Scary part is that object is there, values are there, still, I am getting EXC_BAD_ACCESS. Any ideas why this might be happening?
Let me know if you guys need more info. And thanks in advance for your help. :)
EDIT 1
Definition of Employee and EmployeeForTask (the class declarations are empty and has no variable defined in it, it just inherits from NSManagedObject)
You should enable NSZombies. Zombies helps to detect these kind of crashes by logging problem in console. you can enable zombies by :Click on Product⇒Edit Scheme to open the sheet and set the Enable Zombie Objects check box
When building app on real device then disable Zombies. Otherwise app will not run on device.
I'm trying to debug an EXC_BAD_ACCESS crash using NSZombie. My app creates lots of large objects though and with NSZombie enabled they aren't getting released causing the app to crash in seconds. This means I can't even cause the EXC_BAD_ACCESS crash before the app crashes due to low memory.
Is there an alternative? Can I enable NSZombie on specific file instead of the entire project? How else could I debug this crash (I know it's caused by UIGestureRecognizer but I use them a lot so it doesn't narrow down the issue significantly).
Thanks.
Edit:
Thanks for the advice. I think I may have solved the issue and will report back after more testing.
Edit 2: Sovled the issue myself but selected the answer which seems like it would be a good solution to any similar issues in the future.
All I can think of is implementing it manually; create a proxy container that holds an object of type id and nominates that as -forwardingTargetForSelector: as well as getting it to respond to -isKindOfClass:, etc.
Disable ARC for the proxy and have it retain itself during init and check its own retainCount when nominating a forwarding target.
If the count is 1 then raise an exception or log a warning or whatever.
Have suspect classes wrap themselves in and return a proxy as the last line of their unit.
For possible bonus points, store [NSThread callStackSymbols] somewhere (probably on disk) during the proxy's unit so you can at least find out where the incorrectly managed object was created.
NSZombies was/is for apps that use their own memory management. If your app uses ARC then this won't help.
Create a new Breakpoint: All Exceptions
That should usually show you where you trigger the bad access.
I have a nasty retain cycle in my iOS app. I'm looking at it in instruments and can see all of the retains/releases, but it's hard to track down exactly which retain is the one still holding on.
Does anyone have advice for finding exactly which retain is holding onto the reference?
Edit: Picture of the retain/releases:
You could check out if instruments detects the leak, like so:
From the looks of it, though, that timer near the end of the list doesn't get released.
Could you update your post with the code in setVideoState ?
Edit:
What I usually do is try and match up the retain/releases (instruments should actually do that for you, i think it was some filter in the menu to the left), while focusing on my code, because the frameworks usually have their things together. In your case, as you go down that list you see that the timer has +1 but never get released after that.
I am debugging an iPhone app that was written by someone else, it doesn't use arc. I have tried using arc but they have a lot of old code that uses some c style void pointers, so the program crashes when I do.
I have given up on that idea as a lost cause. The problem is that the allocations / leak tools don't show a memory leak, but the Activity monitor shows memory being leaked every time the user swipes to change a page. (about 1.5 Meg each swipe) Needless to say the program crashes.
Being a c++ programmer myself, with some objective c experience I don't understand all the ins and outs of where the memory is being held onto. Can someone give me some pointers on how to track this one down.
Thanks
I highly recommend spending a day and reading the Objective-C Programming Guide in depth (the retain/release/auto release sections) until it clicks. Also properties which are almost for sure in play here.
Specifically, some memory has been retained by either one too many retains, by a property setter doing that as a side effect, or a view holding onto UI elements (getting hidden but not removed from its super view).
In the Instruments Allocations view, you can see the types of objects that are not getting released - this should help track it down.
Another trick is to put log statements in dealloc methods, to see what large objects are NOT getting released (no log statements in the console).
Your last option is to either post your code and ask for help here, or hire someone to get you past this or to ARCify the code.
EDIT: I had an idea over the weekend on how one might track arbitrary objects - to get an indication of whether they were getting released or not, so I created an Object Tracker project. Using the Tracker class, you can mark objects for tracking, and when the object gets dealloced you'll see a log message in Xcode. Also, you can query the class object to see what objects are still living.
It works by using objc_setAssociatedObject() to attache itself to the tracked object, then logs itself when that object is dealloced (and thus releases the tracker object.
So, you can try a few objects in your project - views, scrollViews, images, arrays, etc, and see if you can at least find the object that isn't getting dealloced when it should be.
Hope this helps.
I've recently finished my first iPhone app that I'm actually planning to submit, and I'm trying to clear out all the leaks. However there's one that I just can't seem to track down, and Instruments isn't really helping me either. Essentially, I've made something like a to-do list app (that's not really important though) and every time a user deletes a to-do, instruments registers a leak.
Instead of me trying to explain further, here's a screenshot:
http://dl.dropbox.com/u/1426380/Screen%20shot%202011-02-09%20at%2021.51.09.png
So instead of telling my exactly where the leak is coming from (like with previous leaks I've fixed), iInstruments just points to somewhere in the foundation library. It's only leaking 16B each time, so it's not really an issue of crashing, but I'm simply interested as to what is causing this.
I would love to post some code, but since I have no idea where the leak is originating, I have no idea what to post. If someone had an insight on what might be causing this, I'd be happy to oblige.
Thanks.
EDIT:
Here's another screenshot as requested by #Moshe. I'm new to instruments so I didn't even realise that the right panel existed until now!
http://dl.dropbox.com/u/1426380/Screen%20shot%202011-02-10%20at%2007.55.58.png
I suggest running "Build and Analyze". (In the Build Menu, or ⌘ + shift + A).
If that returns nothing, it could be that an Apple framework is leaking. If that is the case, there is nothing you can do.