It is not terrible to encounter bugs when writing programs. Most of the problems are caused by simple log or
Code analysis is not difficult to find the cause. However, in objective-C Programming, exc_bad_access
When the problem occurs, 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 (""
), (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
<Foundation/Foundation. h>
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
: @ ""
]. 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 critical issues: 1. Memory leakage. 2. Release error. 3, resulting in exc_bad_access error.
1, nsstring
* S = [[nsstring
Alloc
] Initwithstring
: @ "This is a test string"
]; An nsstring object is created, and the subsequent S = [s substringfromindex
: [S rangeofstring
: @ ""
]. 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, which means that S is the nsstring object we initially created. The second reason is that
Substringfromindex :( nsuinteger I) The nsstring object returned by this method does not need to be released. It is actually
Object marked as autorelease by the substringfromindex method. If we forcibly release it
Exc_bad_access.
3: exc_bad_access. Because the nsstring object to which s points is marked as autorelease
Records already exist in the NSAID utoreleasepool. However, since we released this object in the previous error, when [pool drain]
Now, the nyothoreleasepool calls the release method again for the s object it records.
If it 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, you will see the console output when running the above objective-C:
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} will get the corresponding malloc history, for example, for the previous console output
Untitled [3646: a0f] ***-[cfstring release]: Message sent to deallocated instance 0x10010d340
Then we can execute
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]: thread_7fff70118ca0 | START |
Main | objc_msgsend | lookupmethod | prepareformethodlookup |
_ Class_initialize | + [nsstring initialize] | objc_msgsend | lookupmethod
| Prepareformethodlookup | _ class_initialize | nxcreatemaptablefromzone
| Malloc_zone_malloc
--
Free 0x10010d340-0x10010d357 [size = 24]: thread_7fff70118ca0 | START |
Main | objc_msgsend | lookupmethod | prepareformethodlookup |
_ Class_initialize | _ finishinitializing | free
Alloc 0x10010d340-0x10010d357 [size = 24]: thread_7fff70118ca0 | START |
Main |-[nsplaceholderstring initwithstring:] | objc_msgsend |
Lookupmethod | prepareformethodlookup | _ class_initialize |
_ Class_initialize | + [nsmutablestring initialize] | objc_msgsend |
Lookupmethod | prepareformethodlookup | _ class_initialize |
Nxcreatemaptablefromzone | malloc_zone_malloc
--
Free 0x10010d340-0x10010d357 [size = 24]: thread_7fff70118ca0 | START |
Main |-[nsplaceholderstring initwithstring:] | objc_msgsend |
Lookupmethod | prepareformethodlookup | _ class_initialize |
_ Class_initialize | _ finishinitializing | free
Alloc 0x10010d340-0x10010d35f [size = 32]: thread_7fff70118ca0 | 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.
Of course, there are still many methods to locate exc_bad_access, which vary with specific problems. Welcome to the discussion.