Is there a way to prevent an EXC_BAD_ACCESS from crashing an app, like with #try..#catch you can handle an exception gracefully.
Update:
The code crashes when it attempts to dereference an invalid pointer. This is a third party library and it interfaces with external hardware so I can't debug locally. I am trying to prevent it from crashing and output data to a debugging console on my app.
In ObjC, try/catch do not handle exceptions particularly gracefully. You will still leak memory and leave the system in an undefined state. With rare exception, the expectation is that you are simply catching so you can log some things before crashing. And in general, you should not use #catch anywhere but at the top level of your program for this purpose. There are some extraordinary situations where limited use of exceptions may be appropriate, but they are rare in ObjC. See the Exception Programming Guide for some more information. See especially the following from the ObjC ARC documentation:
The standard Cocoa convention is that exceptions signal programmer error and are not intended to be recovered from. Making code exceptions-safe by default would impose severe runtime and code size penalties on code that typically does not actually care about exceptions safety. Therefore, ARC-generated code leaks by default on exceptions, which is just fine if the process is going to be immediately terminated anyway. Programs which do care about recovering from exceptions should enable the option [-fobjc-arc-exceptions, which imposes speed and memory penalties on your program].
The same is true of EXC_BAD_ACCESS. You can catch it with a signal handler for the purpose of recording some information and then finishing your crash. For a good tool for doing this see PLCrashReporter. It is very difficult to write such a handler correctly, so I strongly recommend using an existing framework. You can easily get into deadlocks that drain the user's battery if you catch EXC_BAD_ACCESS incorrectly.
You get EXC_BAD_ACCESS often because you sent a message to a released object. Then you can examine the NSZombie. What is an NSZombie? You can see : this. It will catch the
EXC_BAD_ACCESS because of sent a message to the released object.
You can set NSZombie like this : Check the Enable Zombie Objects
And you can also get EXC_BAD_ACCESS because of the memory warnings level is too high , or your memory is too high , so the apple will shut your app down. This EXC_BAD_ACCESS is too hard to prevent . I think the only way is to manage your memory as low as you can , sometimes you can see the log where is receive memory warning , when the level is high, it may getEXC_BAD_ACCESS
You can rewrite your code to not have these errors. Try not to reference any null pointers and keep references to any object that you want to have access to.
Related
I am thinking about pros and cons of Try-Catch in Objective-C.
According to this article Dispelling NSException Myths in iOS: Can We Use #try…#catch, #finally?, try-catch isn't that bad, except for it leaks memory in ARC.
So how does try-catch cause memory leak?
First of all: Exceptions have different semantics in Objective-C. An exception means that something went completely wrong because of a programming mistake and the further execution of the application is not useful. Terminate it! To handle "expected errors" (like insufficient user input or not responding servers et al.) use Cocoa's error handling pattern. (The reason for this is that exceptions seems to be convenient in many situation, but are very hard to handle in other situations, i. e. while object construction. Read about exceptions in C++. It is painful.)
To your Q: ARC adds additional code to handle memory management. This code has to be executed to handle the memory management, esp. to release objects. If an exception occurs before this is done, the control flow never reaches the release statement. Memory leaks.
- (void)method
{
id reference = …;
// Some ARC code to retain the object, reference points to.
…
#throw …
…
// reference loses its extent, because of method termination
// Some ARC code to release the object, reference points to.
}
If you have an exception, the method is left immediately and the ARC code and the end of the method to release the object is never executed. This is the leak.
You can change this behavior by compiling the source with -fobjc-arc-exceptions option.
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#exceptions
This will add code to make ARC exception-safe causing a runtime penalty. But there is little reason to do so in Cocoa development, as explained at the beginning of this answer.
As a developer with java background I am used to often catching exceptions to prevent them from crashing my app. This includes all kinds of delegate methods. Just an extra safety measure for unexpected situations.
My question is whether such approach is sensible in objective c and does it introduce some sort of performance problems? I other words would my app suffer in any way if I use try/catch blocks more often?
It won't suffer that much, but you have to remember something. Unlike in other languages where you might have ConnectionRefusedException or FileNonexistantException, in objective-c, exceptions are programmer errors 90% of the time. So by the time your app enters production, it shouldn't have any exceptions anyway. Rather than, for example, catching out of bounds exceptions, just look at array length before trying. You can make a top level try-catch though just in case that gives the error and exits more gracefully than a crash.
In general, you don’t want exceptions to occur while your program is running. So it’s considered better programming practice to test for errors before they occur rather than to catch them after they occur.
It’s also better to test for an error in a method and return some value as an error indicator than to throw an exception.Throwing exceptions use a lot of system resources, and, as such,
Apple generally recommends against using their unnecessary use (e.g., you don’t want to throw an exception simply because you can’t open a file).
Well the best practice is that you use try and catch only when you are loading data, modules, files and things that might not work due to user environment settings or user submitted data.
An exception is an exception, and should not be happening that often : )), so it won't affect performance at all.
Usually protocols contain delegate methods for both normal behaviour and error [e.g. didLoadResponse: theResponse, didFailWithError: theError], so all situations will be covered.
I would reserve exception to situations like errors in writing to disk, or remote servers being down - actually situations that would break the application.
You would have a performance problem.If an exception is thrown, that's fine while you debug the program.But while the application is run by there you may not want that this happens.
My suggestion is to use exceptions only for debug, then you disable them for the release and you use more suitable apporaches like NSError.
Let's suppose that the user types a URL and this URL is invalid.You have to load a web page.During the debug you may just throw an exception, but when you have the release you could just ignore the wrong URL, and don't display the page, or run a NSAlertPanel to display the error.
Use tty/catch for exceptions only, not as a replacement for if/then.Overhead is very expensive.
I just did some testing on an iPad. It appears that a #try/#catch block introduces very little performance penalty unless an exception is actually thrown. But if an exception is thrown, the penalty is substantial. You don't say what environment you are using. So your milage may vary.
In Apple's Concurrency Programming Guide the NSOperation subclass examples (both non-concurrent and concurrent varieties) use exception handling and I'm wondering why they are encouraging this style within operations.
Listing 2-4 Responding to a cancellation request
- (void)main {
#try {
BOOL isDone = NO;
while (![self isCancelled] && !isDone) {
// Do some work and set isDone to YES when finished
}
}
#catch(...) {
// Do not rethrow exceptions.
}
}
My understanding is that generally exception handling is not a common practice in Objective-C code - exceptions are essentially programmer errors and should cause the app to crash whereas unexpected inputs are best handled by NSError. (My possibly misinformed understanding comes from things like this and this)
I'm wondering if NSOperations present a particular situation in which exception handling is important, or if this is more the preferred style of the particular author of that guide.
As a side note, some of the NSOperation example code follows this style, other examples do not. Most high-visibility OSS does not use exceptions (AFNetworking, for example).
Your understanding is correct - NSError (or similar) should be used to convey error information, rather than exceptions. Most Objective-C code is not exception-safe and will at the very least leak resources. As a general rule, never let your code leak an exception into anyone else's code - whether Apple's or a 3rd parties. Some 3rd party frameworks may explicitly indicate they are exception safe, but it's rare.
By that principle you can see why you should have a catch-all exception handler in your main method regardless. But there's actually another reason: your operation will be run on a dedicated thread. Exceptions thrown from your operation will propagate up the stack, but no further. The logical caller or owner of the operation won't get them, as they're running on a different thread (or not at all). So leaked exceptions will either kill your whole program, or be swallowed silently with no other indication. Your program may then get stuck in a weird state - since you didn't realise an error occurred, you may continue waiting for the result of your operation that will never arrive.
Additionally, Apple has a section in the Concurrency Programming Guide where they talk about Handling Errors and Exceptions. Their first point on "discrete entities" is alluding to what I said in the previous paragraph:
Handling Errors and Exceptions
Because operations are essentially
discrete entities inside your application, they are responsible for
handling any errors or exceptions that arise. In OS X v10.6 and later,
the default start method provided by the NSOperation class does not
catch exceptions. (In OS X v10.5, the start method does catch and
suppress exceptions.) Your own code should always catch and suppress
exceptions directly. It should also check error codes and notify the
appropriate parts of your application as needed. And if you replace
the start method, you must similarly catch any exceptions in your
custom implementation to prevent them from leaving the scope of the
underlying thread.
Among the types of error situations you should be prepared to handle
are the following:
Check and handle UNIX errno-style error codes.
Check explicit error
codes returned by methods and functions.
Catch exceptions thrown by
your own code or by other system frameworks.
Catch exceptions thrown
by the NSOperation class itself, which throws exceptions in the
following situations:
When the operation is not ready to execute but
its start method is called
When the operation is executing or finished
(possibly because it was canceled) and its start method is called
again
When you try to add a completion block to an operation that is
already executing or finished
When you try to retrieve the result of
an NSInvocationOperation object that was canceled
If your custom code
does encounter an exception or error, you should take whatever steps
are needed to propagate that error to the rest of your application.
The NSOperation class does not provide explicit methods for passing
along error result codes or exceptions to other parts of your
application. Therefore, if such information is important to your
application, you must provide the necessary code.
I think this post and the accompanying answer elaborates very well on the general exception- vs. no exception handling topic!
It is unsafe to throw exceptions in circumstances where resources are
not automatically managed. This is the case of the Cocoa framework
(and neighbor frameworks), as they use manual reference counting.
If you throw an exception, any release call you skip over by unwinding
the stack will result in a leak. This should limit you tothrowing only
if you're certain that you're not going to recover since all resources
are returned to the OS when a process quits.
Unfortunately, NSRunLoops tend to catch all exceptions that propagate
to them, so if you throw during an event, you'll resume to the next
event. This is, obviously, very bad. Therefore, it's better that you
simply don't throw.
This problem is diminished if you use garbage-collected Objective-C,
as any resource represented by an Objective-C object will be properly
released. However, C resources (such as file descriptors or
malloc-allocated memory) that are not wrapped in an Objective-C object
will still leak.
So, all in all, don't throw.
The Cocoa API has several workarounds to this, as you mentioned.
Returning nil and the NSError** pattern are two of them.
My Mac app is crashing with exc_bad_access on the run loops.
So I enabled NSZombies, and Now I don't see such error as expected ( As the objects are not de-allocated).
But, I don't find any useful NSZombie Log in the console.
Is there a way to identify the issue ?
It's challenging. The most common cause of this error in Cocoa is directly accessing your ivars rather than using accessors. Accessors make the vast majority of memory crashes go away.
That said, they're not the only cause of memory errors. You may be accessing memory other ways. NSZombie does one specific thing: When you deallocate an object, NSZombie says "don't actually deallocate the object." Instead it turns the object into a zombie object that prints an error if you send it messages. But that only helps if the crash is due to sending a message to a deallocated instance. It could be lots of other things.
You should start first with the crash stack itself. Look up the stack and see what kind of object it might be, or who might be calling it.
Read TN2124, particularly the section on the BSD Memory Allocator, and the Enabling the Malloc Debugging Features section of the memory Usage Performance Guidelines. There are lower-level tools than NSZombie that you can use. MallocScribble is often the most useful. It overwrites deallocated memory with 0x55 so that you're more likely to crash sooner, and to make it easier to detect deallocated memory in the debugger. MallocPreScribble is useful for finding uninitialized memory, but this really only helps if you do raw malloc calls. ObjC objects are always pre-initialized.
And of course you have to put on your detective hat. What parts of your program are most suspicious? Are you doing multi-threaded work (that can cause memory crashes if you don't lock correctly).
If it reproduces easily, then you'll figure it out. If it only happens occasionally, well... I've hunted bugs like that for many months sometimes. Sometimes it's just hard.
You need to use memory profiler for that. Just build with Profile option and select Leaks.
I am really interested to know that, Is it possible that using try ... catch mechanism, we can avoid memory crash of our application ... ??
Let say the program part that we are expecting a chance of memory leak is kept under try...catch block, if the program crashes (ie memory leak) occurs then catch statement execute. So we can prevent our program from being crashed.
Is it possible ? If yes, How Or If not , why not ??
A try/catch block is there to catch an exception and stop it from propagating upwards in your callstack.
The idea goes that you catch it at the place where you know how to handle it, and then you get a chance to execute code in response to the exception.
It is not a magical solution that will prevent anything, it is just what I said above. What you do with the exception is what matters.
And a memory leak and a crash is not the same thing, it is rare that a program crashes due to memory leaks, unless it actually runs out of memory. A memory leak is rarely "fixable" after the fact. The correct, and usually only, way to fix a memory leak is to avoid it happening in the first place.
Also, yes, in a way you can keep your program from crashing by adding try/catch blocks all over, but the only thing you've succeeded in is to hide the crash from the user, and then let the program continue running. "Crashes" are not always safe to ignore, or rather, they are usually not safe to ignore.
If you are looking for some catch-all advice on how to avoid a program crashing, here's my advice:
Write a program that works correctly
I think we need to know more about what kinds of problems you're having, or you need to post a clearer question.
I would not trust any in process system to do the right thing in case of an out of memory condition. We have systems which completely lock up when a PermGen exception occurs and need a kill -9 to get rid off.
If you want the system to self correct, wrap it in a script or a system which monitors the health, a heart beat or a diagnostics page or whatever makes sense. If you receive no health indication kill it (hard if necessary) and restart it.
Best of all is to use testing and validation to include monitoring the memory (and disk) usage and make sure you really know how your system behaves and is properly configured so it does not happen.
The restarting solution is a poor alternative, because you then must test and ascertain that you can kill your application at any time and be confident it can be restarted correctly, which might even be more difficult.
If you are asking "can I catch segmentation faults with try catch", the answer is no.
try catch is for handling Objective-C exceptions i.e. those raised by executing an #throw statement. Segmentation faults caused by e.g. null pointer dereferences are generated by the operating system and are examples of Unix signals and can only be caught and handled by OS level system calls e.g. the sigaction(2) system call. Even then, the only sane thing you can do is terminate the program immediately because you might have a corrupt heap or stack.