在 Visual Studio 中測量記憶體使用量 (C#、Visual Basic、C++、F#)

當您進行偵錯時,您可以使用與偵錯工具整合的 [記憶體使用量] 診斷工具,來找出記憶體遺漏和記憶體使用沒有效率等問題。 記憶體使用量工具可讓您擷取受控 原生之記憶體堆積的一或多個「快照」,以利了解物件類型的記憶體使用量影響。 您也可以在沒有附加偵錯工具的情況下分析記憶體使用量,或透過以執行中應用程式為目標進行此分析。 如需詳細資訊,請參閱使用或不使用偵錯工具來執行分析工具。 如需為您的需求選擇最佳記憶體分析工具的詳細資訊,請參閱選擇記憶體分析工具

除了可以在 記憶體使用量 工具中收集任何時間的記憶體快照之外,您還可以使用 Visual Studio 偵錯工具,來控制調查效能問題時要如何執行應用程式。 設定中斷點、逐步偵錯、全部中斷和其他偵錯工具動作,都可以協助您將效能調查工作集中在最相關的程式碼路徑上。 在應用程式執行時進行那些動作,可排除您不感興趣之程式碼的干擾,並可大幅縮短診斷問題所需的時間。

重要

Visual Studio 中的 .NET 開發支援偵錯工具整合的診斷工具,包括 ASP.NET、ASP.NET Core、原生/C++ 開發,以及混合模式 (.NET 和原生) 應用程式。 Windows 8 及更新版本必須執行附有偵錯工具的分析工具 ([診斷工具] 視窗)。

在此教學課程中,您需要:

  • 擷取記憶體的快照
  • 分析記憶體使用量資料

如果 [記憶體使用量] 未給與您所需的資料,則效能分析工具中的其他分析工具會提供可能對您有所幫助的不同種類資訊。 在許多情況下,應用程式的效能瓶頸可能是記憶體以外的問題所導致,例如 CPU、呈現 UI 或網路要求時間。

注意

自訂配置器支援 原生記憶體分析工具的運作方式是收集在執行階段所發出的配置 ETW 事件資料。 在來源層級已註釋 CRT 和 Windows SDK 中的配置器,以便擷取其配置資料。 如果您正在撰寫自己的配置器,則針對任何將指標傳回最新配置之堆積記憶體的函式,都可以使用 __declspec(allocator) 來裝飾,如本範例中針對 myMalloc 所示:

__declspec(allocator) void* myMalloc(size_t size)

收集記憶體使用量資料

  1. 開啟您想要在 Visual Studio 中偵錯的專案,並於應用程式中要開始檢查記憶體使用量的位置設定中斷點。

    如果您懷疑某個區域具有記憶體問題,請在記憶體問題發生之前設定第一個中斷點。

    提示

    由於當應用程式頻繁地配置和解除配置記憶體時,擷取您感興趣之作業的記憶體設定檔可能會是項挑戰,因此請在作業開始和結束處 (或是逐項順著作業) 設定中斷點,以找出記憶體變更的實際點。

  2. 在您想要分析的函式或程式碼區域結尾 (或是在可能的記憶體問題發生之後) 設定第二個中斷點。

  3. [偵錯工具] 視窗會自動出現,除非您將其關閉。 如需再次顯示視窗,請按一下 [偵錯]>[Windows]>[顯示診斷工具]

  4. 以工具列上的 [選取工具] 設定選擇 [記憶體使用量]

    Screenshot of Diagnostics Tools.

    Screenshot of Diagnostics Tools.

  5. 按一下 [偵錯/開始偵錯] (或工具列上的 [開始]F5)。

    應用程式完成載入時,會出現 [診斷工具] 的 [摘要] 檢視。

    Screenshot of Diagnostics Tools Summary Tab.

    注意

    由於收集記憶體資料可能會影響原生或混合模式應用程式的偵錯效能,因此預設會停用記憶體快照。 若要在原生或混合模式應用程式中啟用快照,請啟動偵錯工作階段 (快速鍵:F5)。 在顯示 [診斷工具] 視窗時,選擇 [記憶體使用量] 索引標籤,然後選擇 [堆積分析]

    Screenshot of Enable snapshots.

    停止 (快速鍵:Shift+F5) 並重新開始偵錯。

    Screenshot of Diagnostics Tools Summary Tab.

    注意

    由於收集記憶體資料可能會影響原生或混合模式應用程式的偵錯效能,因此預設會停用記憶體快照。 若要在原生或混合模式應用程式中啟用快照,請啟動偵錯工作階段 (快速鍵:F5)。 在顯示 [診斷工具] 視窗時,選擇 [記憶體使用量] 索引標籤,然後選擇 [堆積分析]

    Screenshot of Enable snapshots.

    停止 (快速鍵:Shift+F5) 並重新開始偵錯。

  6. 若要在偵錯工作階段開始時擷取快照,請選擇 [記憶體使用量] 摘要工具列上的 [擷取快照]。 (在此設定中斷點也可能會有幫助)。

    Screenshot of Take Snapshot button.

    Screenshot of Take Snapshot button.

    提示

    若要建立記憶體的比較基準,請考慮擷取偵錯工作階段開始時的快照。

  7. 執行會叫用您的第一個中斷點的案例。

  8. 當偵錯工具於第一個中斷點暫停時,選擇 [記憶體使用量] 摘要工具列上的 [擷取快照]

  9. F5 使應用程式執行至第二個中斷點。

  10. 現在請擷取另一個快照。

    此時,您可以開始分析資料。

    如果您無法收集或顯示資料,請參閱針對分析錯誤進行疑難排解並修正問題

分析記憶體使用量資料

[記憶體使用量] 摘要表的資料列會列出您在偵錯工作階段期間擷取的快照集,並提供更詳細檢視的連結。

Screenshot of Memory Usage table.

Screenshot of Memory Usage table.

每個資料行的名稱則取決於您在專案屬性中選擇的偵錯模式:.NET、原生或混合 (.NET 和原生)。

  • [物件 (差異)] 和 [配置數 (差異)] 資料行顯示擷取快照時 .NET 和原生記憶體中的物件數目。

  • [堆積大小 (差異)] 資料行顯示 .NET 和原生堆積中的位元組數目

當您擷取多個快照之後,摘要表的資料格會包含資料列快照與上一個快照之間的值變更。

若要分析記憶體使用量,請按一下其中一個可以開啟記憶體使用量詳細報表的連結:

  • 若要檢視目前快照與上一個快照之間的差異詳細資料,請選擇箭號左邊 (Memory Usage Increase) 的變更連結。 紅色箭號表示記憶體使用量增加,綠色箭號表示減少。

提示

為了協助使用者更快速地識別記憶體問題,差異報表會以整體數目增加最多 (按一下 [物件 (差異)] 資料行中的變更連結),或整體堆積大小增加最多 (按一下 [堆積大小 (差異)] 資料行中的變更連結) 的物件類型來分類。

  • 若只要檢視所選快照的詳細資料,請按一下未變更連結。

    報表會在個別的視窗中顯示。

Managed 類型報表

選擇 [記憶體使用量] 摘要表中 [物件 (差異)] 或 [配置數 (差異)] 儲存格的目前連結。

Screenshot of managed type report.

Screenshot of managed type report.

上方窗格顯示快照中所有類型的計數和大小,包括類型參考之所有物件的大小 ([內含大小])。

下方窗格中的 [根的路徑] 樹狀結構顯示參考在上方窗格中選取之類型的物件。 您必須釋放參考物件的最後一個類型,.NET 記憶體回收行程才會清除該物件的記憶體。

[參考的物件] 樹狀結構顯示上方窗格中所選類型保留的參考。

Screenshot of Referenced Objects report.

[參考的類型] 樹狀結構顯示在上方窗格中選取之類型所持有的參考。

Screenshot of Referenced Objects report.

若要顯示上方窗格中所選類型的執行個體,請按一下物件類型旁邊的 [檢視執行個體]。

Screenshot of the Instances view in the Memory Usage tool.

Screenshot of the Instances view in the Memory Usage tool.

[執行個體] 檢視顯示在上方窗格的快照中選取之物件的執行個體。 [根的路徑] 和 [參考的物件] 窗格顯示參考所選執行個體的物件,以及所選執行個體參考的類型。 當偵錯工具在建立快照集的位置停止時,您可以將滑鼠停留在 [值] 資料格,以在工具提示中顯示物件的值。

原生類型報表

在 [診斷工具] 視窗的 [記憶體使用量] 摘要表中,選擇 [配置數 (差異)] 或 [堆積大小 (差異)] 儲存格的目前連結。

Screenshot of Native Type View.

Screenshot of Native Type View.

[類型檢視] 顯示快照中所有類型的數目和大小。

  • 選擇所選類型的執行個體圖示 (The instance icon in the Object Type column),以顯示快照集中所選類型的物件相關資訊。

    [執行個體] 檢視顯示所選類型的每個執行個體。 選取執行個體會顯示在 [配置呼叫堆疊] 窗格中建立執行個體時所產生的呼叫堆疊。

    Screenshot of the Instances view and Allocation Call Stack pane.

  • 選擇所選類型旁邊的 [檢視執行個體],以顯示快照集中所選類型的物件相關資訊。

    [執行個體] 檢視顯示所選類型的每個執行個體。 選取執行個體會顯示在 [配置呼叫堆疊] 窗格中建立執行個體時所產生的呼叫堆疊。

    Screenshot of the Instances view and Allocation Call Stack pane.

  • 在 [檢視模式] 清單中選擇 [堆疊檢視] ,以查看所選類型的配置堆疊。

    Screenshot of Stacks view.

  • 選擇 [堆疊] 以查看所選類型的配置堆疊。

    Screenshot of Stacks view.

記憶體使用量深入解析

針對受控記憶體,記憶體分析工具也會提供多個功能強大的內建自動深入解析。 選取 [受控類型] 報表中的 [深入解析] 索引卷標,並顯示適用的自動深入解析,例如重複字串疏鬆數位事件處理程式流失

Screenshot of the insight view in the Memory Usage tool.

[重複字串] 區段會顯示堆積上多次配置的字串清單。 此外,此區段也會顯示浪費的記憶體總量,亦即 (執行個體數目 - 1) 乘以字串的大小。

[疏鬆陣列] 區段會顯示大部分填入零元素的陣列,這在效能和記憶體使用量方面可能效率低下。 記憶體分析工具會自動偵測這些陣列,並顯示由於這些零值而浪費多少記憶體。

Visual Studio 2022 17.9 版 Preview 1 中提供的 [事件處理程式流失] 區段會顯示某個物件訂閱另一個物件事件時可能發生的記憶體流失。 如果事件的發佈者比訂閱者存活得更久,則訂閱者仍然會保持存活的狀態 (即使沒有其他的參考指向它也一樣)。 這可能會導致記憶體洩漏 (即未使用的記憶體沒有被正確地釋放),進而導致應用程式隨著時間的移動而使用越來越多的記憶體。

已知某些類型具有可讀取的欄位,以判斷其所保留的原生記憶體大小。 [深入解析] 索引標籤會顯示物件圖形中的假原生記憶體節點,這些節點是由其父物件保留,以便 UI 能夠辨識這些節點並顯示其大小和參考圖表。

Screenshot of the native insight view in the Memory Usage tool.

變更 (差異比對) 報表

  • 在 [診斷工具] 視窗中,選擇 [記憶體使用量] 索引標籤摘要表資料格中的變更連結。

    Screenshot of Choose a change link in a cell.

    Screenshot of Choose a change link in a cell.

  • 在 Managed 或原生報表的 [比較] 清單中,選擇一個快照。

    Screenshot of Choose a snapshot from the Compare To list.

    Screenshot of Choose a snapshot from the Compare with list.

變更報表會將顯示基礎快照值與比較快照之間有差異的資料行 (標記為 [(差異比對)] ),加入基礎報表。 以下是原生類型檢視差異比對報表可能的樣子:

Screenshot of Native Types Diff View.

Screenshot of Native Types Diff View.

部落格和影片

Analyze CPU and Memory While Debugging (偵錯時分析 CPU 與記憶體)

Visual C++ Blog: Memory Profiling in Visual C++ 2015 (Visual C++ 部落格:Visual C++ 2015 中的記憶體分析)

下一步

在本教學課程中,您已了解如何收集並分析記憶體使用量資料。 如果您已完成分析工具導覽,則可能想要閱讀有關使用分析工具最佳化程式碼的一般方法。

在本教學課程中,您已了解如何在偵錯時收集並分析記憶體使用量資料。 您可能想要深入了解如何使用效能分析工具,來分析發行組建中的記憶體使用量。