I'm having a bug in my Objective C program which causes the machine to crash hip deep in some library methods, and it's all library methods down the stack to main (Which I haven't touched from the one XCode gave me). So, I have a bit of a mystery.
The error I'm getting is:
Program received signal: “EXC_BAD_ACCESS”.
Now, I'm sure that this means that somewhere I'm releasing something too many times, or something like that. This is the objective C version of a seg-fault, right?
My question is: Since it's not happening in my own code, is there some clever way of tracking down what I'm double releasing? or is code inspection the best bet?
thanks.
EXC_BAD_ACCESS essentially means that you're trying to access or use a specific chunk of memory in an unexpected way. For example, if you try to send a message to a memory reference that no longer represents a valid object. It's different from a segmentation fault, but related.
See this related SO question for suggestions on debugging over-released objects. NSZombie will work wonders for you. Once you get your hands on Snow Leopard (you're getting it this Friday, right?) use the Zombies instrument to simplify the process, and use the Xcode static analyzer to help you find such errors at compile time.
Also visit: http://www.cocoadev.com/index.pl?DebuggingTechniques and this Apple Tech Note.
Related
My program crashes after indicating the following. I know something bad occured with the NSArrays. How should I trace the array variable which causes the exception?
Tracing the array isn't going to help you here that much (but see below). You've overreleased something, probably the NSArray itself, and you're not finding out about it until the autorelease pool drains. These can be some of the hardest bugs to track down; hopefully it reproduces consistently.
The typical solutions are:
Make sure you're using ARC. This is precisely the kind of bug that ARC does an excellent job of avoiding. (And usually this kind of crash suggests you're not using it; but it is possible to get them under ARC in some cases.)
Work out which NSArray is having trouble. Audit its usage and make sure that (if you're not using ARC), you are following the memory management rules at each point. Regarding "work out which NSArray," this can be tricky in itself, but some common sense often is the best tool here. You probably have some sense of what object it is. A little trial and error can go a long way.
Avoid direct ivar access; always use accessors except in init and dealloc. This is the best way (besides ARC) to avoid these kinds of memory errors.
Instruments can add traces on retains and releases (use the Zombies instrument). And there is NSZombies, which can help as well. But I have found in the vast majority of cases, the best first step is to search for all the times you use the object, and then check your retains and releases by hand. (I'm not saying any of these approaches is easy; just that a quick by-hand audit is often more effective than the tools.)
And of course make sure to use ARC.
The BEST way to do this, which will help you on MANY occasions, is to set up XCode to automatically break when exceptions are thrown where they are thrown. You can do this as follows:
STEP 1: Go to the breakpoints navigator.
STEP 2: Go to the bottom left and hit '+' and add exception breakpoint.
STEP 3: Find the breakpoint you just added above, right-click, and edit.
STEP 4: Change it to break on all Objective-C exceptions, and the vast majority of crashes will break where the crash occurred.
When the exception occurs, you can act as if you're normally debugging - print values to the console, or hover over them to see what their values are.
Is there a way to find a Zombie at runtime in objective-c?
I'm looking for a way to prevent an object to call a method on a zombie, is there any way to detect one without making the app crash?
I do know about weak reference under ARC iOS5 and common sense programming practice.
I was thinking that a way could be asking the object size (I know that maybe "inside" there are just reference) but if the object still exist it should give a value, if it doesn't probably just the single pointer size.
Using malloc_size(pointerToObject)
Could it work?
UPDATE:
I do know how to run Instruments for Zombies detection
I don't think Andrea is asking how to run instruments to detect zombies, I think she wants to guard against calling a dealloced instance at runtime. I'm not sure what malloc size will return in this case. I think anything you come up with short of what they've done with NSZombies (which is to never truly free instances) will be gimicky and only work part of the time. I think your best best is the boring old diligent programming and profiling with instruments to guard against making these calls rather than trying to catch the error at runtime.
Try running the application with Instruments, and select the "Zombies" template.
On the scheme menu (upper left, next to run/stop). Select "Edit Scheme...". A sheet will appear. Select the Run/Debug scheme there. Select the "Diagnostics" tab on the center pane. Check Zombies.
I'm newish to Objective-C and my memory management skills are not great. However, I haven't had a single problem until now. And now I've got big problems.
I've gone from zero crashes to crashing at random points, giving me either no console output or unrecognized selector errors on random types (-[NSCFSet isSameAsStop:]: unrecognized selector - I don't even use any sets and I surely have not called my custom isSameAsStop on any sets.). Judging by the randomness and errors, it seems like a memory thing to me although I'm not entirely sure.
How do I go about debugging this? The debugger assumes you know where your problem is... and mine is just everywhere. Ideas?
SOLUTION COMMENT
Some clarification on the solution suggestion to "run with zombie detection enabled":
Set the NSZombieEnabled to YES on the Executables' Arguments screen.
Build and then choose Run with Performance Tool > Object Allocations, which will start Instruments.
Click the "i" button on Object Allocations in Instr. and select zombie detection and retain counts.
Rerun and click around in your app, it'll tell you when you hit a zombie!
Thanks for the help!
You have a classic over-release bug on your hands. Somewhere, you are over-releasing an instance of the class that implements isSameAsStop and it just so happens that an NSSet instance is allocated at the same spot after the original instance is deallocated.
The first step is to "build and analyze" your code, fixing any problems that the static analyzer finds.
The next step is to then run with zombie detection enabled.
In Xcode: Build menu >> Build and Analyze
Finds a lot of common memory management issues.
I'd like to use gdb or Xcode's debugger to watch every message sent to an object in an Objective-C 2.0 program. I don't care about arguments and such, as I just need to see every message it receives (retain, release, autorelease, etc). I also don't want to profile my entire program.
Is there a means, in Xcode, to select an instance (possibly by address) and say "show me every message sent to this object"? Since the plumbing is fairly standard, I imagine there would have to be a probe hook or something. Anyone ever done this?
(Aside from subclassing the object in question, of course; looking for a more general solution.)
This is for iPhone development with Xcode 3.2 on Snow Leopard.
You can set the NSObjCMessageLoggingEnabled environment variable to YES and then grep/filter through the resulting log for the object you're interested in.
Here's a relevant blog post as well, though I'm not sure how much of the information there is still true in the runtime today. (It might all be. I really don't know.)
Memory (and resource) leaks happen. How do you make sure they don't?
What tips & techniques would you suggest to help avoid creating memory leaks in first place?
Once you have an application that is leaking how do you track down the source of leaks?
(Oh and please avoid the "just use GC" answer. Until the iPhone supports GC this isn't a valid answer, and even then - it is possible to leak resources and memory on GC)
In XCode 4.5, use the built in Static Analyzer.
In versions of XCode prior to 3.3, you might have to download the static analyzer. These links show you how:
Use the LLVM/Clang Static Analyzer
To avoid creating memory leaks in the first place, use the Clang Static Analyzer to -- unsurprisingly -- analyse your C and Objective-C code (no C++ yet) on Mac OS X 10.5. It's trivial to install and use:
Download the latest version from this page.
From the command-line, cd to your project directory.
Execute scan-build -k -V xcodebuild.
(There are some additional constraints etc., in particular you should analyze a project in its "Debug" configuration -- see http://clang.llvm.org/StaticAnalysisUsage.html for details -- the but that's more-or-less what it boils down to.)
The analyser then produces a set of web pages for you that shows likely memory management and other basic problems that the compiler is unable to detect.
If your project does not target Mac OS X desktop, there are a couple of other details:
Set the Base SDK for All Configurations to an SDK that uses the Mac OS X desktop frameworks...
Set the Command Line Build to use the Debug configuration.
(This is largely the same answer as to this question.)
Don't overthink memory management
For some reason, many developers (especially early on) make memory management more difficult for themselves than it ever need be, frequently by overthinking the problem or imagining it to be more complicated than it is.
The fundamental rules are very simple. You should concentrate just on following those. Don't worry about what other objects might do, or what the retain count is of your object. Trust that everyone else is abiding by the same contract and it will all Just Work.
In particular, I'll reiterate the point about not worrying about the retain count of your objects. The retain count itself may be misleading for various reasons. If you find yourself logging the retain count of an object, you're almost certainly heading down the wrong path. Step back and ask yourself, are you following the fundamental rules?
Always use accessor methods; declare accessors using properties
You make life much simpler for yourself if you always use accessor methods to assign values to instance variables (except in init* and dealloc methods). Apart from ensuring that any side-effects (such as KVO change notifications) are properly triggered, it makes it much less likely that you'll suffer a copy-and-paste or some other logic error than if you sprinkle your code with retains and releases.
When declaring accessors, you should always use the Objective-C 2 properties feature. The property declarations make the memory management semantics of the accessors explicit. They also provide an easy way for you to cross-check with your dealloc method to make sure that you have released all the properties you declared as retain or copy.
The Instruments Leaks tool is pretty good at finding a certain class of memory leak. Just use "Start with Performance Tool" / "Leaks" menu item to automatically run your application through this tool. Works for Mac OS X and iPhone (simulator or device).
The Leaks tool helps you find sources of leaks, but doesn't help so much tracking down the where the leaked memory is being retained.
Follow the rules for retaining and releasing (or use Garbage Collection). They're summarized here.
Use Instruments to track down leaks. You can run an application under Instruments by using Build > Start With Performance Tool in Xcode.
I remember using a tool by Omni a while back when I was trying to track down some memory leaks that would show all retain/release/autorelease calls on an object. I think it showed stack traces for the allocation as well as all retains and releases on the object.
http://www.omnigroup.com/developer/omniobjectmeter/
First of all, it's vitally important that your use of [ ] and { } brackets and braces match the universal standard. OK, just kiddin'.
When looking at leaks, you can assume that the leak is due to a problem in your code but that's not 100% of the fault. In some cases, there may be something happening in Apple's (gasp!) code that is at fault. And it may be something that's hard to find, because it doesn't show up as cocoa objects being allocated. I've reported leak bugs to Apple in the past.
Leaks are sometimes hard to find because the clues you find (e.g. hundreds of strings leaked) may happen not because those objects directly responsible for the strings are leaking, but because something is leaking that object. Often you have to dig through the leaves and branches of a leaking 'tree' in order to find the 'root' of the problem.
Prevention: One of my main rules is to really, really, really avoid ever allocating an object without just autoreleasing it right there on the spot. Anywhere that you alloc/init an object and then release it later on down in the block of code is an opportunity for you to make a mistake. Either you forget to release it, or you throw an exception so that the release never gets called, or you put a 'return' statement for early exit somewhere in the method (something I try to avoid also).
You can build the beta port of Valgrind from here: http://www.sealiesoftware.com/valgrind/
It's far more useful than any static analysis, but doesn't have any special Cocoa support yet that I know of.
Obviously you need to understand the basic memory management concepts to begin with. But in terms of chasing down leaks, I highly recommend reading this tutorial on using the Leaks mode in Instruments.