<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-193  評論-715  文章-1  trackbacks-0
    原文地址: http://www.cocoachina.com/macdev/objc/2011/0219/2661.html

    寫程序遇到 Bug 并不可怕,大部分的問題,通過簡單的 Log 或者 代碼分析并不難找到原因所在。但是在 Objective-C 編程中遇到 EXC_BAD_ACCESS 問題的時候,通過簡單常規(guī)的手段很難發(fā)現問題。

        寫程序遇到 Bug 并不可怕,大部分的問題,通過簡單的 Log 或者 代碼分析并不難找到原因所在。但是在 Objective-C 編程中遇到 EXC_BAD_ACCESS 問題的時候,通過簡單常規(guī)的手段很難發(fā)現問題。這篇文章,給大家介紹一個常用的查找 EXC_BAD_ACCESS 問題根源的方法。

        首先說一下 EXC_BAD_ACCESS 這個錯誤,可以這么說,90%的錯誤來源在于對一個已經釋放的對象進行release操作。舉一個簡單的例子來說明吧,首先看一段Java代碼:

    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);
                    
            }
    }

        這種寫法在Java中很常見也很普遍,這不會產生任何問題。但是到了 Objective-C 中,就會出事,考慮這個程序:

    #import <Foundation/Foundation.h>

    int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
            NSString* s = [[NSString alloc]initWithString:@”This is a test string”];
            s = [s substringFromIndex:[s rangeOfString:@"a"].location];//內存泄露
            [s release];//錯誤釋放
    [pool drain];//EXC_BAD_ACCESS
    return 0;
    }


        這個例子當然狠容易的看出問題所在,如果這段代碼包含在一個很大的邏輯中,確實容易被忽略。Objective-C 這段代碼有三個致命問題:1、內存泄露;2、錯誤釋放;3、造成 EXC_BAD_ACCESS 錯誤。

        1, NSString* s = [[NSString alloc]initWithString:@”This is a test string”]; 創(chuàng)建了一個 NSString Object,隨后的 s = [s substringFromIndex:[s rangeOfString:@"a"].location]; 執(zhí)行后,導致創(chuàng)建的對象引用消失,直接造成內存泄露。

        2,錯誤釋放。[s release]; 這個問題,原因之一是一個邏輯錯誤,以為 s 還是我們最初創(chuàng)建的那個 NSString 對象。第二是因為從 substringFromIndex:(NSUInteger i) 這個方法返回的 NSString 對象,并不需要我們來釋放,它其實是一個被 substringFromIndex 方法標記為 autorelease 的對象。如果我們強行的釋放了它,那么會造成 EXC_BAD_ACCESS 問題。

        3, EXC_BAD_ACCESS。由于 s 指向的 NSString 對象被標記為 autorelease, 則在 NSAutoreleasePool 中已有記錄。但是由于我們在前面錯誤的釋放了該對象,則當 [pool drain] 的時候,NSAutoreleasePool 又一次的對它記錄的 s 對象調用了 release 方法,但這個時候 s 已經被釋放不復存在,則直接導致了 EXC_BAD_ACCESS問題。

        那么,知道了 EXC_BAD_ACCESS 的誘因之一后,如何快速高效的定位問題?

    1: 為工程運行時加入 NSZombieEnabled 環(huán)境變量,并設為啟用,則在 EXC_BAD_ACCESS 發(fā)生時,XCode 的 Console 會打印出問題描述。

    首先雙擊 XCode 工程中,Executables 下的 可執(zhí)行模組,

    在彈出窗口中,Variables to be set in the environment,添加 NSZombieEnabled,并設定為 YES,點擊選中復選框啟用此變量。

        這樣,運行上述 Objective-C 時會看到控制臺輸出:Untitled[3646:a0f] *** -[CFString release]: message sent to deallocated instance 0x10010d340

        這條消息對于定位問題有很好的提示作用。但是很多時候,只有這條提示是不夠的,我們需要更多的提示來幫助定位問題,這時候再加入 MallocStackLogging 來啟用malloc記錄。


        當錯誤發(fā)生后,在終端執(zhí)行:

    malloc_history ${App_PID} ${Object_instance_addr}

        則會獲得相應的 malloc 歷史記錄,比如對于上一個控制臺輸出

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

        則我們可以在終端執(zhí)行,結果如下:

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

    Date/Time: 2011-02-01 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

        這樣就可以很快的定位出問題的代碼片段了,注意輸出的最后一行,,,這行雖然不是問題的最終原因,但是離問題點已經很近了,隨著它找下去,八成就會找到問題。

    posted on 2012-01-05 16:18 Robin's Programming World 閱讀(853) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲视频小说图片| 亚洲av中文无码乱人伦在线播放 | 国色精品卡一卡2卡3卡4卡免费 | 亚洲精品中文字幕无码AV| 国精产品一区一区三区免费视频 | 日韩亚洲变态另类中文| 免费国产a理论片| 亚洲国产专区一区| 国产免费MV大全视频网站| 久久久久亚洲爆乳少妇无| 久久久精品国产亚洲成人满18免费网站 | 亚洲精品亚洲人成在线| 黄页免费的网站勿入免费直接进入| 亚洲国产精品美女| 99视频在线精品免费观看6| 国产精品亚洲综合久久| 日本免费一区二区三区最新vr| 久久久久亚洲国产AV麻豆| 亚洲精品第一国产综合境外资源| 黄视频在线观看免费| 亚洲va久久久噜噜噜久久| 57pao国产成视频免费播放| 91在线亚洲综合在线| 亚洲成a人片在线观看老师| 日本免费A级毛一片| 亚洲欧洲日产国码二区首页| 成人黄软件网18免费下载成人黄18免费视频 | 亚洲五月午夜免费在线视频| 亚洲av永久无码制服河南实里| 99在线精品视频观看免费| 精品无码专区亚洲| 亚洲av午夜福利精品一区| 在线a级毛片免费视频| 成年网站免费入口在线观看| 亚洲AV无码久久精品蜜桃| 青春禁区视频在线观看直播免费 | 自怕偷自怕亚洲精品| 在线观看国产情趣免费视频 | 久久WWW色情成人免费观看| 性生大片视频免费观看一级| 78成人精品电影在线播放日韩精品电影一区亚洲 |