官术网_书友最值得收藏!

8.2 高級調試技巧

8.2.1 遠程調試

遠程調試是Visual Studio的一個強大功能,當你的程序在其他計算機上運行時,可以通過遠程調試來正常地調試程序。Xcode 4.2版本也有一個WiFi調試功能,類似于遠程調試,但由于不穩定,在之后的版本中被移除了。

遠程調試功能強大,但操作起來并不麻煩,首先需要在目標機器以管理員身份運行遠程調試監視器,可以在Visual Studio的安裝目錄下找到,如圖8-15所示。

圖8-15 監視器目錄

x64和x86分別對應64位和32位的操作系統,將目錄復制到目標機器,然后運行目錄下的msvsmon.exe,啟動監視器后,可以在工具→選項中設置調試的端口、身份驗證模式、空閑時間等屬性,如圖8-16所示。如果不在同一個內網,需要選擇“無身份驗證”模式,使用該模式是存在一定風險的。

圖8-16 設置遠程調試監視器

服務器就緒后,可以在Visual Studio中選擇“調試”→“附加到進程”命令,在彈出的“附加到進程”對話框中,選擇“傳輸”下拉列表框中的“遠程(無身份驗證)”選項,然后在“限定符”中輸入遠程的IP和端口,按Enter鍵之后會刷新出可以掛載的進程列表,再選擇目標計算機中要調試的程序,即可進行調試,如圖8-17所示。

圖8-17 附加到遠程進程

需要注意的是本地的代碼和pdb文件需要與我們要調試的目標程序匹配,否則無法進行斷點調試。所以在發布一個調試版本時,最好打一個分支或者將項目保存一份,然后不再修改。當不需要遠程調試時,應該將遠程調試監視器及時關閉,在需要調試時再開啟。

8.2.2 coredump調試

如果不方便進行遠程調試,而又希望獲得程序崩潰時的堆棧等信息,那么可以使用Windows系統的coredump進行調試,Linux系統也有該機制。

在程序崩潰時會自動生成coredump, Windows系統下需要設置一下,在“系統屬性”對話框中單擊“啟動和故障恢復”欄的“設置”按鈕,在彈出對話框中選擇“核心內存轉儲”選項,如圖8-18所示。而Linux系統下則只需要執行一條ulimit -c unlimited命令即可。

圖8-18 生成coredump

單擊“寫入調試信息”下的下拉按鈕,可以選擇“核心內存轉儲”,選擇完之后還可以設置coredump文件存放的路徑。也可以在Windows的任務管理器中,右擊選擇崩潰的進程,然后選擇創建轉儲文件,如圖8-19所示。

圖8-19 生成轉儲文件

找到生成的DMP文件并雙擊,會啟動Visual Studio,選擇右側的僅限本機進行調試按鈕,Visual Studio會自動加載項目和pdb文件(項目不能修改或移動),然后就可以定位到程序崩潰時的堆棧了,讀者可以自己寫一段崩潰的代碼測試一下。

8.2.3 使用Bugly捕獲崩潰堆棧

前面介紹了Windows下崩潰堆棧的獲取方法,但是Cocos2d-x做的并不是Windows游戲,而是手機游戲,所以這里介紹一個專門監控Android和iOS平臺下崩潰信息的庫Bugly。這是騰訊提供的一個第三方庫,在Cocos2d-x下可以很方便地使用,網址為https://bugly.qq.com/cocossdk。官方文檔很清楚地介紹了如何接入,以及如何使用。

登錄Bugly可以看到所有的崩潰上報,有哪些地方崩潰了,崩潰了多少次,影響了多少個用戶,用戶的設備是什么型號,崩潰的時間,剩余的內存和磁盤空間等。在首頁會有BUG列表,可以進行版本的篩選,只查看最新版本的崩潰信息,也可以只查看某渠道的崩潰信息,以及指定時間內的崩潰信息。

如圖8-20是BUG的詳情頁面,左側的列表為同樣的BUG的多次上報記錄,下方的“出錯線程”面板顯示了崩潰堆棧,除了C++的崩潰,Lua的崩潰也會有詳細的堆棧,“系統日志”面板則上報了崩潰時輸出的日志,使用CCLOG打印出的信息會被上報到這里(但日志條數有數量限制)。

圖8-20 BUG詳情頁面

8.2.4 命中斷點

斷點是調試程序最核心的功能之一,當我們命中了一個斷點之后,程序會中斷,然而斷點只能中斷嗎?當然不是,我們可以讓斷點在命中之后不中斷,而是執行某些操作,如打印出當前的某些變量或者堆棧等。Visual Studio中可以在斷點上右擊選擇命中條件,會彈出如圖8-21所示對話框,在其中選擇“打印信息”后可以輸入所要打印的信息。

圖8-21 命中斷點設置

我們可以輸入$開頭的特殊關鍵字,如$PID、$CALLSTACK等,也可以輸入一個變量或表達式,用{}包裹住,命中斷點時會打印出變量或表達式的值。選擇“繼續執行”可以讓斷點命中之后繼續執行,而不是中斷。

需要注意的是設置了命中斷點之后,程序運行的效率會降低不少,而且前面設置的條件斷點會失效,但可以在代碼中添加一個條件判斷,在條件判斷成功后執行一行代碼,在這行代碼中設置命中條件,也可以起到過濾的作用。

Xcode在命中斷點之后可以執行的處理更為豐富,而且與命中條件并不沖突,在命中斷點之后,可以執行以下動作。

? AppleScript執行一段Apple腳本,AppleScript是Apple推出的一門強大的腳本語言。

? Capture GPU Frame捕獲當前GPU所繪制的幀,用于輔助圖形調試。

? Debugger Command可以執行lldb的調試命令,如使用bt命令輸出當前堆棧。

? Log Message可以在調試窗口輸出一個消息,可以用@var@來打印表達式。

? Shell Command可以執行一個shell指令。

? Sound可以讓Xcode播放一個系統聲音。

如圖8-22所示,通過單擊右側的“+”按鈕,可以添加多個Action。選中最下方Options后的復選框,還可以讓斷點命中之后繼續執行,而不是中斷。

圖8-22 Xcode編輯斷點

8.2.5 數據斷點

Visual Studio的數據斷點可以設置一個地址,當這個地址對應的內存被修改時斷住。當我們發現某個地址被莫名其妙地修改時,就可以借助數據斷點來定位問題,選擇“調試”→“新建斷點”→新建數據斷點”命令,可以打開數據斷點的設置對話框,如圖8-23所示。

圖8-23 數據斷點

有時候我們會碰到一種越界訪問的BUG,當出現了這樣的BUG,并且程序沒有立刻崩潰時,問題就變得很隱蔽了,可能會在任何正常的地方崩潰,如一個vector的push_back()方法,并且同一個問題導致的崩潰可能每一次都不一樣,如果沒有經驗,那么這種BUG解決起來就非常痛苦了。

由于C/C++操作指針或者數組時很容易越界,越界之后訪問的可能是某個類的內部結構,當對越界的內存進行寫入操作時,就會破壞這些類的內部結構,從而導致崩潰。由于崩潰的地方與崩潰的原因毫無關系,所以這類問題比較難以解決,當發現不應該崩潰的代碼莫名其妙地崩潰時,就要看看是否出現了越界操作。下面是常見的越界操作。

        //首先定義了數組,然后對數組進行初始化,實際上這個初始化是對a的第65個元素賦值,很有
        隱蔽性
        char a[64];
        a[64] = { 0 };
        //內存復制,dst沒有足夠的內存空間或復制的長度錯誤,會覆蓋dst后面的內存
        memcpy(dst, src, sizeof(src));
        //還是內存復制,原本應該復制到buffer->data的,但是直接復制到了buffer
        buffer->data = new char[len];
        memcpy(buffer, src, len);
        //字符串格式化,參數傳漏或緩沖區不夠大,都可能導致溢出,應該使用snprintf
        sprintf(buf, "%s, %d, %s", str1, num1);

除了使用數據斷點監視指定的內存是否被修改,還可以在崩潰處逆推,檢查前方的代碼是否存在類似上述的問題,特別是指針相關的操作。

另外還可以用排除法,屏蔽掉部分代碼來分析問題,還可以通過svn或git來分析是哪個版本提交的代碼之后導致的問題,縮小查找范圍。利用這些經驗,以后再碰到了莫名其妙的問題之后就不至于手足無措了。

8.2.6 即時窗口

即時窗口是Visual Studio提供的一個實時調試窗口,可以在即時窗口輸入指令來打印變量、執行語句以及計算表達式等,如圖8-24所示。

圖8-24 即時窗口

之所以提供這么一個即時窗口,是因為其真的非常靈活,例如,當我們希望分析一塊內存,這塊內存是由各種數據結構組成的,通過即時窗口可以很方便地檢查這些結構的賦值是否正確,如服務器下發了一塊內存數據,對應的一系列結構體。此外,在分析的時候還可以執行各種表達式和語句,包括直接執行一些成員函數,用于對代碼進行單元測試也是非常不錯的。

在Xcode下的輸出窗口,也屬于可以實時進行調試的窗口,它是一個lldb命令行窗口,lldb類似GDB,是一個強大的命令行調試工具,詳情讀者可以查閱官方的這篇lldb初學者教程,網址為http://lldb.llvm.org/tutorial.html

8.2.7 多線程調試

當調試多線程程序時,它們執行的同一段代碼可能會被多次中斷,如果希望只針對某一個線程進行調試,則可以在斷點上右擊,在快捷菜單中選擇“添加斷點篩選器”命令,在彈出的對話框中設置線程ID的篩選條件,如圖8-25所示。

圖8-25 設置斷點篩選器

8.2.8 性能調試

Visual Studio和Xcode都提供了強大的性能分析工具,幫助解決性能問題,Visual Studio中可以使用菜單上的“分析”→“性能與診斷”命令,運行性能向導,如圖8-26所示。

圖8-26 性能與診斷

單擊“開始”按鈕,然后一直選擇下一步,就會將程序運行起來,運行一段時間結束程序后,Visual Studio會自動生成分析報告。

我們可以選擇CPU采樣,也可以選擇檢測函數執行的耗時,單擊生成的分析報告,可以查看耗時最多的函數,并標識出函數對應的代碼視圖。通過這個視圖,可以輕易地分析出哪些方法的性能消耗比較大,從而有針對性地進行優化。雙擊左右兩側的藍色函數窗口,可以在函數堆棧中上下切換,觀察消耗,如圖8-27所示。

圖8-27 性能分析詳情

Xcode的性能分析工具更加強大,Xcode的Instruments提供了一系列的分析工具,除了性能分析之外,還有內存泄漏、GPU、動畫、網絡、系統I/O等一系列的分析工具,在Xcode中選擇Product→Profile命令,會彈出如圖8-28所示的界面,在界面中選擇Time Profiler。

圖8-28 Instruments

在Xcode菜單中選擇Open Developer Tools→Instruments命令,也可以打開Instruments界面,但在這里打開只能附加在已運行的進程中,而通過Product→Profile這種方式打開則是調試當前程序。

選擇Time Profile之后,會彈出Time Profile的信息界面,如圖8-29所示。單擊左上角的紅色圓圈按鈕(不是關閉),之后會開始性能分析,然后改按鈕變為黑色的方塊形狀,其旁邊的按鈕可以暫停程序。

圖8-29 CPU性能分析

在CPU Usage的右側會出現CPU使用的曲線圖,曲線圖直觀地反映了程序運行時CPU的占用情況。曲線圖的下方羅列了性能消耗最多的函數,單擊這些函數我們可以一點一點打開,觀察該函數執行的消耗點,也可以用鼠標在曲線圖上單擊,框選某一段時間,觀察指定時間內的性能消耗,默認統計的是整個程序運行周期中的性能消耗。

主站蜘蛛池模板: 南漳县| 自治县| 肇庆市| 麦盖提县| 垣曲县| 南康市| 舟山市| 安庆市| 百色市| 上高县| 石城县| 通道| 酒泉市| 井陉县| 罗江县| 磴口县| 大关县| 巩义市| 独山县| 汽车| 晋州市| 赞皇县| 扎赉特旗| 武邑县| 天全县| 高安市| 新安县| 芜湖县| 枣阳市| 宝山区| 霍州市| 岐山县| 隆林| 鄯善县| 安庆市| 布尔津县| 久治县| 房产| 仪陇县| 上虞市| 攀枝花市|