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.