How to find the root cause of the EXC_BAD_ACCESS Problem

Source: Internet
Author: User
Www.cocoachina.commacw.bjc201102192661.html it is not terrible to encounter bugs when writing a program. For most of the problems, it is not difficult to find the cause through simple Log or code analysis. However, when the problem of EXC_BAD_ACCESS is encountered in Objective-C programming, it is difficult to find the problem through simple and conventional means. This article

Http://www.cocoachina.com/macdev/objc/2011/0219/2661.html programming encountered bugs is not terrible, most of the problems, through simple Log or code analysis is not difficult to find the cause. However, when the problem of EXC_BAD_ACCESS is encountered in Objective-C programming, it is difficult to find the problem through simple and conventional means. This article

Http://www.cocoachina.com/macdev/objc/2011/0219/2661.html


It is not terrible to encounter bugs when writing programs. Most of the problems are difficult to find the cause through simple Log or code analysis. However, when the problem of EXC_BAD_ACCESS is encountered in Objective-C programming, it is difficult to find the problem through simple and conventional means. This article describes a common method for finding the root cause of the EXC_BAD_ACCESS problem.

First, let's talk about the EXC_BAD_ACCESS error. It can be said that the 90% error is caused by the release operation on a released object. Let's take a simple example. First, let's look at a piece of Java code:

Public class Test {
Public static void main (String [] args ){
String s = "This is a test string ";
S = s. substring (s. indexOf ("a"), (s. length ()));
System. out. println (s );

}
}

This method is common and common in Java, which does not cause any problems. But in Objective-C, there will be an accident. Consider this program:

# Import

Int main (int argc, const char * argv []) {
NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];
NSString * s = [[NSString alloc] initWithString: @ "This is a test string"];
S = [s substringFromIndex: [s rangeOfString: @ "a"]. location]; // Memory leakage
[S release]; // release Error
[Pool drain]; // EXC_BAD_ACCESS
Return 0;
}

In this example, the problem is easily identified. If the code is included in a large logic, it is indeed easy to ignore. The Objective-C code has three fatal problems: 1. Memory leakage; 2. Release of errors; 3. EXC_BAD_ACCESS error.

1, NSString * s = [[NSString alloc] initWithString: @ "This is a test string"]; creates an NSString Object, and then s = [s substringFromIndex: [s rangeOfString: @ "a"]. location]; after execution, the created object reference disappears, directly causing memory leakage.

2. Release error. [S release]; one of the reasons for this problem is a logic error, thinking that s is the NSString object we initially created. The second reason is that the NSString object returned from the substringFromIndex :( NSUInteger I) method does not need to be released. It is actually an object marked as autorelease BY THE substringFromIndex method. If we forcibly release it, it will cause EXC_BAD_ACCESS problems.

3, EXC_BAD_ACCESS. Because the NSString object to which s points is marked as autorelease, there is a record in the ntutoreleasepool. However, because we released this object in the previous error, when [pool drain], the NSAID utoreleasepool again called the release method for the s Object recorded by it, but at this time s has been released and no longer exists, it directly causes the EXC_BAD_ACCESS problem.

Then, after learning about one of the incentives for EXC_BAD_ACCESS, how can we quickly and efficiently locate the problem?

1: add the NSZombieEnabled environment variable to the project runtime and set it to enable. When EXC_BAD_ACCESS occurs, the XCode Console prints the Problem description.

Double-click the executable modules under Executables in the XCode project,

In the displayed window, Variables to be set in the environment, add NSZombieEnabled, and set it to YES. Click the check box to enable this variable.

In this way, when running the above Objective-C, you will see the console output: Untitled [3646: a0f] ****-[CFString release]: message sent to deallocated instance 0x10010d340

This message is helpful for locating problems. However, many times, this prompt is not enough. We need more prompts to help locate the problem. At this time, we will add MallocStackLogging to enable malloc records.


When an error occurs, run the following command on the terminal:

Malloc_history $ {App_PID }$ {Object_instance_addr}

The corresponding malloc history will be obtained, for example, for the output of the previous Console

Untitled [3646: a0f] ***-[CFString release]: message sent to deallocated instance 0x10010d340

Then we can run the command on the terminal. The result is as follows:

Buick-Wongs-MacBook-Pro: Downloads buick $ malloc_history 3646 0x10010d340
Malloc_history Report Version: 2.0
Process: Untitled [1, 3646]
Path:/Users/buick/Desktop/Untitled/build/Debug/Untitled
Load Address: 0 ×100000000
Identifier: Untitled
Version :??? (???)
Code Type: X86-64)
Parent Process: gdb-i386-apple-darwin [3638]

Date/Time: 15:07:04. 181 + 0800
OS Version: Mac OS X 10.6.6 (10J567)
Report Version: 6

ALLOC 0x10010d340-0x10010d357 [size = 24]: principal | start | main | objc_msgSend | lookUpMethod | percent | _ class_initialize | + [NSString initialize] | objc_msgSend | lookUpMethod | prepareForMethodLookup | _ class_initialize | percent
--
FREE 0x10010d340-0x10010d357 [size = 24]: thread_7fff70118ca0 | start | main | objc_msgSend | lookUpMethod | prepareForMethodLookup | _ class_initialize | _ finishinitializfree |

ALLOC 0x10010d340-0x10010d357 [size = 24]: thread_7fff70118ca0 | start | main |-[NSPlaceholderString initWithString:] | objc_msgSend | lookUpMethod | prepareForMethodLookup | _ class_initialize | + [NSMutableString initialize] | objc_msgSend | lookUpMethod | percent | _ class_initialize | percent |
--
FREE trial [size = 24]: Snapshot | start | main |-[NSPlaceholderString initWithString:] | objc_msgSend | lookUpMethod | percent | _ class_initialize | _ finishInitializing | free

ALLOC failed [size = 32]: Failed | start | main |-[NSCFString substringWithRange:] | CFStringCreateWithSubstring | _ CFStringCreateImmutableFunnel3 | _ CFRuntimeCreateInstance | malloc_zone_malloc

In this way, you can quickly locate the problematic code snippet. Pay attention to the last line of output. Although this line is not the final cause of the problem, it is very close to the problem point, as it goes on, it will find the problem.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.