Freigeben über


Visual Studio 2013的進階偵錯與效能分析技巧

作者 – 王寧疆

偵錯是排除應用程式執行錯誤的重要技巧,當資訊系統日趨複雜,執行環境愈來愈多樣化,如何有效地偵錯應用程式發生的種種異常狀況是程式設計師需要努力的目標,本文將說明Visual Studio
2013在協助開發者分析應用程式品質與診斷應用程式錯誤的實用功能。

 

  • Code Map除錯及架構應用 - 視覺化檢視模組、呼叫堆疊及逆向工程

 

傳統的程式開發者在了解應用程式的模組、類別、或功能之間的關係,或是偵錯應用程式功能錯誤的時候,大都只能透過檢視原始程式碼,或是開發工具提供的呼叫堆疊檢視,來了解應用程式的功能或是發掘應用程式的錯誤,但這都只能提供給開發者最基本的文字型式資訊而已,不但很難勾勒出整個應用程式的全貌,更重要的是程式開發團隊如果要檢視和應用程式中某個模組、類別、和功能相關的所有程式碼,例如檢視所有呼叫到某個方法的程式碼,或是某個方法呼叫到的所有其他方法,幾乎只能求助於開發工具提供的搜尋功能,而搜尋得到的結果仍舊是以文字的格式呈現,造成程式開發團隊在維護複雜的應用程式,都是一件極吃力的負擔。

        針對這個問題, Visual Studio 2013提供能夠將應用程式的功模組、類別、和功能,甚至的搜尋原始程式碼的結果建立成易於檢視的架構圖,不但可以讓程式開發團隊綜觀應用程式的全貌,更可以讓程式開發團隊能夠以一目瞭然的方式看到程式碼的問題所在,縮短修正程式錯誤的時間,降低維護成本

 

以圖形化的資訊支援程式開發團隊維護和偵錯應用程式的功能在尋找功能面的錯誤有極高的效率與價值,是以文字檢視為主的傳統程式碼檢視無法達到的境界,例如程式開發團隊可以利用Code Map功能檢視方法參考的類別變數,發掘程式是否用錯變數以外,也可以透過檢視方法之間的呼叫關係挖掘應用程式的功能錯誤。

 

        例如圖1為一個簡單的資料庫程式,使用者可以利用 [新增]頁籤的功能新增資料庫記錄,並利用 [瀏覽]頁籤的功能瀏覽資料庫中的記錄:

 

圖1: 範例程式

        但是使用者在操作上述的應用程式之後向程式開發團隊反應,新增到資料庫的記錄無法利用[瀏覽]頁籤檢視。這時候開發者就可以利用Visual Studio
2013提供的Code Map功能檢視負責查詢資料庫記錄的方法 (上述例子是利用TableAdapter類別的Fill方法執行查詢資料庫記錄的工作) 之所有參考,以了解為什麼使用者新增的資料庫記錄沒有即時呈現在檢視畫面中。

 

        使用滑鼠的右鍵點選原始程式中TableAdapter類別的Fill方法,執行 [尋找Code Map上的所有參考]功能之後,您會看到如圖2的畫面,表示應用程式中只有名稱為Form1_Load的方法會呼叫TableAdapter類別的Fill方法,以執行查詢資料庫記錄的動作,難怪使用者透過 [新增] 頁籤新增的資料庫記錄無法立即在 [瀏覽]頁籤檢視。

 

圖2:檢視TableAdapter類別的Fill方法在Code Map上所有參考的結果畫面

 

        看到這樣的結果之後,程式開發者就可知道,新增的資料庫記錄因為缺少重新查詢資料庫記錄的動作,而沒有即時呈現在檢視資料庫記錄的畫面上。要解決這個問題,我們只要在使用者切換頁籤引發的SelectedIndexChanged事件處理程序中,加入呼叫TableAdapter類別的Fill方法之程式碼,就可以讓使用者立即於 [瀏覽]頁籤檢視到新增的資料庫記錄。修正後的應用程式Code Map類似圖3:

 

圖3:修正後的Fill方法之Code Map

        從上述的例子可以看出,Code Map功能在尋找程式功能面的錯誤的確有極高之效率與價值,開發者幾乎只要建立Code Map架構圖,不需要執行大量的搜尋動作,就可以輕鬆地了解程式功能異常的問題所在。

 

Code Map於逆向工程的應用

 

        開發者也可以利用Code Map功能對現有的專案執行逆向工程,用以建立架構圖,深入了解複雜的應用程式架構與功能之關係,並快速地了解應用程式的基礎結構。

 

        例如使用滑鼠右鍵點中專案中的類別名稱,從出現的功能表選擇 [在Code Map上顯示]功能,再展開Code Map中代表類別的圖示,就可以看到類別的完整功能,或是使用滑鼠右鍵點中類別中的方法名稱,執行 [在Code Map上顯示相關項目 | 顯示這一項呼叫的方法]功能,檢視所選定的方法呼叫到的其他方法,以了解方法之間的相依性與呼叫關係。圖4即為檢視程式中名稱為GetImageAsync的方法呼叫所有方法之Code Map圖:

 

圖4:檢視應用程式中名稱為GetImageAsync的方法呼叫所有方法之Code Map圖

 

Code Map 的視覺化呼叫堆疊資訊

除了可以利用Code Map功能了解應用程式的架構,偵錯功能面的錯誤以外,也可以將呼叫堆疊資訊以視覺化的方式呈現,讓開發者能夠對應用程式的執行內容一目瞭然,甚至是利用視覺化的檢視,以發掘應用程式的錯誤。

        要以視覺化的方式檢視[呼叫堆疊]的資訊,請先利用中斷點讓應用程式進入中斷狀態,然後按下 [偵錯] 工具列中的 [Code Map]
按鈕,Visual Studio 2013就會將應用程式的呼叫堆疊資訊以視覺化的方式呈現,如圖5:

 

圖5:以視覺化的方式呈現呼叫堆疊資訊的Code Map功能

 

        請注意Code Map功能顯示的視覺化呼叫堆疊資訊中橘紅色的方塊,代表現在執行的程式碼,當您繼續以追蹤執行的方式偵錯,Code Map顯示的視覺化資訊也會隨著應用程式的執行而同步更新。點選Code Map視覺化檢視顯示的方塊,再點選出現的突現式工具列提供的 [建立新註解節點] 按鈕,為方塊代表的按鈕加入註解說明,也可以使用滑鼠的左鍵點選視覺化檢視顯示的方塊兩下,移至方塊代表的方法之原始程式碼。

 

        如果您想要知道程式中有那些地方,呼叫到這些方塊所代表的方法,可以使用滑鼠右鍵,點選該方塊,再從功能表選擇 [尋找所有參考] 功能,Visual Studio
2013就會顯示所有呼叫此方法的其他方法。如果想要知道該方塊所代表的方法使用的類別變數,則從功能表選擇 [顯示這一項參考的欄位] 功能,就會顯示該方法使用到的類別變數。可以利用這兩個功能檢查方法是否使用到正確的類別變數,而不是使用到方法的區域變數,或者是否有呼叫到正確的方法,進而找到應用程式的錯誤。

 

  • 傾印檔案分析(Dump Analysis) - .NET應用程式記憶體使用狀況

傾印檔案分析 (Dump
Analysis) 功能可分析.NET應用程式的記憶體使用狀況,包括網頁程式、資料庫應用程式、和Windows Form程式是否有記憶體使用不當、不必要的記憶體配置、以及Memory Leak等問題。當出現上述記憶體使用的問題時,可能會發生記憶體不足的情形,進而造成電腦執行效能下降。請注意,要分析.NET應用程式記憶體使用的情形,您必須使用Visual Studio
Ultimate 2013,而且選擇 .NET Framework 4.5或更高版本做為執行平台。

 

  [ 注意] 分析記憶體傾印檔的功能只支援.NET應用程式的記憶體使用狀況,不支援分析Windows巿集應用程式。

 

        欲取得程式執行時的記憶體傾印檔,請先啟動Visual Studio
2013,以偵錯的方式執行應用程式,並進入中斷狀態,然後執行 [ 偵錯 | 另存傾印 ] 功能,將應用程式的狀態儲存成副檔名為 .dmp的傾印檔。之後用Visual Studio
2013開啟該傾印檔案,您將會看到如圖6所示的畫面:

 

圖6:使用Visual Studio 2013開啟傾印檔案的畫面

 

        開啟傾印檔之後,請點選畫面左方的 [偵錯Managed記憶體] 連結,如圖7:

 

圖7:偵錯 .NET應用程式的記憶體使用畫面

 

請注意現在的Visual Studio已經進入偵錯狀態。從圖7的上半部看到各種型態的資料的數量,以及佔用的記憶體總數,當您點選其中的某個類型時,圖7的下半部就會顯示所有使用到被選取的型態之物件型態,以及造成該型態無法被Garbage Collector回收機制回收的物件型態。

 

        程式開發者可以在不同的時間點建立應用程式的記憶體傾印檔,再將先建立的記憶體傾印檔當做基準進行比較,以了解兩個不同的時間點建立的記憶體傾印檔是否有物件的數量異常增加的情形,如果物件數量有異常增加,代表有可能是物件沒有被成功回收。

        當您建立多個不同的記憶體傾印檔之後,就可以點選圖7畫面中的 [選取基準] 下拉選項中的 [瀏覽],再選取做為比較基準的記憶體傾印檔,就可以比較兩個記憶體傾印檔之間的差異,再將差異顯示在 [計數差異] 與 [總共大小差異] 欄位中供檢視,能夠很清楚地了解兩次比較之間物件數量與物件佔用的記憶體數量差異,以發掘物件未能夠被成功回收的原因,並加以排除。

 

        圖8即為兩個不同的記憶體傾印檔比較結果,第二次記錄記憶體傾印檔時System.EventHandler型態的物件增加了500個,總佔用的記憶體大小也增加了16,000位元組,而MemoryLeak.MyClass型態的物件也增加了500個,總佔用的記憶體大小則增加了6,000位元組。

 

圖8:兩個不同記憶體傾印檔的比較結果

 

        點選圖8中數量異常增加的物件,下方顯示資訊就可以了解該型態的物件不能被回收之原因。例如圖8顯示的MemoryLeak.MyClass型態的物件無法被成功回收,是因為被System.EventHandler型態的物件使用中。

 

  • DOM總管與JavaScript主控台 – 進階的JavaScript偵錯

 

執行 [偵錯 | 視窗 |
JavaScript主控台] 功能,或是執行 [偵錯 | 視窗 | DOM總管]功能,開啟 [JavaScript主控台] 或是 [DOM總管] 視窗,協助偵錯JavaScript相關的錯誤。Visual
Studio 2013支援 [DOM總管] 視窗支援IntelliSense功能提示、搜尋、於 [樣式] 頁籤直接新增或編輯樣式、或是使用滑鼠右鍵點選HTML標籤,從出現的功能選擇[加入屬性] 或 [當成HTML編輯]功能,直接編輯網頁的內容。Visual
Studio 2013支援的 [JavaScript主控台] 同樣支援IntelliSense功能提示、物件預覽與視覺化檢視,以及編輯包含多行程式碼的函數等功能。圖9所示即為於 [JavaScript主控台] 輸入:

 

console.dir(x>today);

 

圖9:預覽x變數的內容是否大於today變數的內容結果

 

除此之外,使用JavaScript開發Windows巿集應用程式可進行JavaScript與C++語言之間的混合偵錯。

 

  • Performance and Diagnostics功能

這是最新加入的應用程式效率診斷功能,包括分析程式中那些函式消耗最多的CPU資源、電源數據、以及利用XAML文件建立使用者介面的Windows巿集應用程式的使用者介面反應性是否良好,協助開發者發掘並排除應用程式潛在的問題。

啟動Visual Studio
2013之後執行 [分析 | Performance and
Diagnostics] 功能,啟動[Performance and Diagnostics] 功能,會出現如圖10的畫面:

 

圖10:[Performance and Diagnostics] 功能啟動的畫面

 

        您可以勾選畫面中的 [CPU取樣]、[Energy
Consumption]、[XAML UI Responsiveness]做為效能分析與診斷的方向,也可以利用 [Change
Target]選擇欲診斷的應用程式,包括方案中的啟始專案、執行中的應用程式、安裝的應用程式、EXE應用程式、或是IIS管理的網站。按下 [開始]鍵,會自動啟動被診斷的應用程式供您操作,操作完應用程式的功能之後請關閉應用程式,就會自動執行分析與診斷,並做成報告供檢視。如圖11:

 

圖11:執行 [CPU取樣] 分析報告

 

        請注意圖11畫面中的 [最忙碌路徑] 項目顯示的是耗費最多CPU時間的功能,其中 [專有%] 欄位顯示的數值是該方法執行實際花費的CPU時間,點選最忙碌路徑顯示的項目連結,可檢視更詳細內容。

 

圖12:執行 [Energy Consumption]分析的結果報告

 

        其中的 [用電量摘要] 顯示的數據表示該次診斷消耗的總電池時間,包括估計電池的壽命可以支撐該次診斷的操作動作多久時間。

 

圖13:執行 [XAML UI Responsiveness] 分析報告

        您必須點選包含使用者介面定義的XAML文件,例如MainPage.xaml,才能看到使用者介面的反應數據。

 

  • Windows巿集應用程式非同步偵錯支援

以非同步的技術所呼叫之功能,因為程式尚未執行結束,所以較難取得相關的資訊,嘗試取得相關的資訊容易造成舊版的Visual Studio本身執行的問題,也造成除錯的困難度,這些問題到了Visual Studio
2013都已經得到了改善。利用 [呼叫堆疊] 視窗檢視以非同步方式呼叫的方法,與利用 [工作] 視窗檢視更多平行運算工作的相關資訊,圖14即為利用Visual Studio
2013偵錯使用async / await非同步技術所開發的Windows巿集應用程式:

 

圖14:偵錯非同步執行的Windows巿集應用程式與 [呼叫堆疊] 視窗內容

 

程式設計師也可以利用 [工作] 視窗檢視非同步作業的相關資訊。圖15即為執行 [偵錯 | 視窗 | 工作] 功能,了解目前執行工作的資訊:

 

圖15:利用 [工作] 視窗檢視應用程式目前執行的工作

除此之外,使用C++程式語言開發的Windows巿集應用程式也可以捕捉Windows
Runtime(WinRT)元件執行發生,所有繼承自Platform::Exception類別的衍生類別例外的堆疊資訊,您只要在 [監看式] 視窗監看$exceptiontrace變數的內容值,並展開這個變數的詳細內容,就可以巡覽至發生例外的原始程式碼。

 

  • 程式碼分析功能的改善

程式碼分析功能,用以分析應用程式潛在的問題,是一種預防性偵錯,使用Visual Studio
2013執行程式碼分析的警告訊息會直接顯示在 [程式碼分析] 視窗,它支援更佳的篩選、排序、以及分類功能,提供更好的程式碼分析結果管理,如圖16:

 

圖16:執行程式碼分析的結果

 

  • C++ 程式的Just My Code偵錯支援

 

Just My Code偵錯可以在利用 [呼叫堆疊] 視窗檢視程式的堆疊資訊時,隱藏非應用程式本身的模組,例如.NET平台、Windows Runtime、或是協力廠商的模組,讓你能夠聚焦在自己的程式碼進行偵錯。Visual Studio
2013預設會啟用Just My Code功能,您必須執行 [偵錯 | 選項和設定] 功能,再清除 [啟用Just My Code] 的勾選狀態,才能夠在 [呼叫堆疊] 視窗看到所有被呼叫,但是尚未結束執行的模組。

 

圖17:啟用Just My Code及未啟用的 [呼叫堆疊] 視窗差異

 

  •      其他好用的偵錯功能

除了上述的功能外,Visual Studio
2013支援對64位元應用程式進行 [編輯後繼續]偵錯,偵錯時可以立即修改原始程式碼,並在不需要重新建置專案的狀況下觀察修改後的程式碼的執行結果。

 

        支援在 [自動變數] 視窗自動顯示並未儲存至變數的函數傳回值內容是Visual Studio
2013另一好用偵錯功能,方便檢視函數呼叫的結果。圖18即為利用 [自動變數]視窗檢視呼叫Random類別的NextDouble方法與Next方法的傳回值畫面,不需要另外宣告變數承接呼叫方法的傳回值,就可以很方便地檢視。

 

圖18:[自動變數] 視窗檢視呼叫Random類別的NextDouble方法與Next方法的傳回值

 

[ 提示 ] 使用[監看式]視窗進行偵錯時可以自行輸入名稱為$ReturnValue的變數,以檢視最近一個呼叫方法的傳回值。

 

 

延伸閱讀

  [線上功能展示影片]