通过


测量Visual Studio中的内存使用情况(C#、Visual Basic、C++、F#)

使用调试器集成的 内存使用情况 诊断工具进行调试时,查找内存泄漏和低效内存。 通过内存使用率工具可以拍摄一个或多个托管和本机内存堆的快照,帮助理解对象类型的内存使用率影响。 还可以在不附加调试器的情况下或通过面向正在运行的应用来分析内存使用情况。 有关详细信息,请参阅在发行版本或调试版本上运行分析工具。 有关根据需要选择最佳内存分析工具的信息,请参阅 选择内存分析工具。

尽管可以随时在 Memory Usage 工具中收集内存快照,但可以使用Visual Studio调试器来控制应用程序在调查性能问题时的表现。 断点设置、步进、全部中断和其他调试器操作可以帮助将性能调查集中在最相关的代码路径上。 在应用程序运行时执行这些操作可以消除你不感兴趣的代码中的干扰,并能显著减少诊断问题所需的时间。

提示

还可以使用 GitHub Copilot Profiler Agent 获得由 AI 驱动的指南,用于收集和分析内存跟踪。

重要

Visual Studio 支持用于 .NET 开发的调试器集成诊断工具,包括 ASP.NET、ASP.NET Core、本机/C++ 开发以及混合模式(.NET 和本机)应用。

在本教程中,你将:

  • 拍摄内存快照
  • 分析内存使用情况数据

如果 内存使用率 不提供所需的数据,性能探查器中的其他分析工具 提供可能有用的不同类型的信息。 在许多情况下,应用程序的性能瓶颈可能是由内存以外的内容(例如 CPU、呈现 UI 或网络请求时间)引起的。

备注

自定义分配器支持 本机内存探查器的工作原理是收集在运行时发出的分配 ETW 事件数据。 CRT 和 Windows SDK 中的分配器在源级别上注释,因此可以捕获其分配数据。 如果您在编写自己的分配器,那么返回新分配的堆内存指针的任何函数都可以使用 __declspec(allocator)进行修饰,如 myMalloc 示例中所示:

__declspec(allocator) void* myMalloc(size_t size)

收集内存使用情况数据

  1. 打开要在Visual Studio中调试的project,并在要开始检查内存使用情况的点在应用中设置断点。

    如果你有一个怀疑内存问题的区域,请设置内存问题发生前的第一个断点。

    提示

    由于当应用程序频繁分配和释放内存时,要捕获您感兴趣的操作的内存配置文件可能比较困难,因此请在操作的开始和结束时设置断点(或逐步执行操作)以查找内存更改的确切点。

  2. 在要分析的函数或代码区域的末尾设置第二个断点(或在出现可疑内存问题后)。

  3. 诊断工具 窗口将自动显示,除非你已将其关闭。 若要再次打开窗口,请单击 调试Windows显示诊断工具。

  4. 使用工具栏上的 “选择工具” 设置,选择 内存使用情况。

    “诊断工具”窗口的屏幕截图,其中“选择工具”下拉列表中选择了“内存使用情况”工具。

    “诊断工具”窗口的屏幕截图,其中“选择工具”下拉列表中选择了“内存使用情况”工具。

  5. 单击 调试/开始调试(或单击工具栏上的 开始,或按 F5)。

    应用完成加载后,将显示诊断工具的“摘要”视图。

    “诊断工具摘要”选项卡的屏幕截图,其中显示了“内存使用情况时间线图”和“处理内存”图表。

    备注

    由于收集内存数据可能会影响本机或混合模式应用的调试性能,因此默认禁用内存快照。 若要在本机或混合模式应用中启用快照,请启动调试会话(快捷键:F5)。 出现“诊断工具”窗口时,选择“内存使用情况”选项卡,然后选择 堆分析。

    内存使用情况工具栏的屏幕截图,其中突出显示了“堆分析”按钮,为本机或混合模式应用启用快照。

    停止(快捷键:ShiftF5)并重启调试。

    “诊断工具摘要”选项卡的屏幕截图,其中显示了“内存使用情况时间线图”和“处理内存”图表。

    备注

    由于收集内存数据可能会影响本机或混合模式应用的调试性能,因此默认禁用内存快照。 若要在本机或混合模式应用中启用快照,请启动调试会话(快捷键:F5)。 出现“诊断工具”窗口时,选择“内存使用情况”选项卡,然后选择 堆分析。

    内存使用情况工具栏的屏幕截图,其中突出显示了“堆分析”按钮,为本机或混合模式应用启用快照。

    停止(快捷键:ShiftF5)并重启调试。

  6. 若要在调试会话开始时拍摄快照,请选择 在 内存使用情况 摘要工具栏上拍摄快照。 (在此处设置断点可能也会有所帮助。)

    “拍摄快照”按钮的“内存使用情况摘要”工具栏的屏幕截图。

    提示

    若要创建内存比较基线,请考虑在调试会话开始时创建快照。

  7. 运行会触发第一个断点的方案。

  8. 当调试器在第一个断点暂停时,请选择 在 内存使用情况 摘要工具栏上拍摄快照。

  9. 按 F5 将应用运行到第二个断点。

  10. 现在,拍摄另一个快照。

此时,可以开始分析数据。

如果在收集或显示数据时遇到问题,请参阅 排查分析错误并修复的问题。

分析内存使用情况数据

“内存使用情况摘要”表中的行会列出在调试会话期间拍摄的快照,并提供指向更详细视图的链接。

内存使用情况摘要表的屏幕截图,其中显示了两个快照,其中包含对象、堆大小及其差异列。

列的名称取决于在项目属性中选择的调试模式:.NET、本机代码或混合模式(即.NET和本机代码)。

  • Objects (Diff) (.NET) 或 Allocations (Diff) (C++) 列显示拍摄快照时.NET或本机内存中的对象数。

  • Heap Size(Diff) 列显示 .NET 和本地堆中的字节数

当您创建多个快照后,摘要表的单元格将显示当前行快照与上一快照相比的数值变化。

若要分析内存使用情况,请单击其中一个链接,打开内存使用情况的详细报告:

  • 若要查看当前快照与上一快照之间的差异的详细信息,请选择箭头左侧的更改链接(内存使用量增加内存使用量增加)。 红色箭头表示内存使用量增加,绿色箭头表示减少。

提示

为了帮助更快识别内存问题,差异报告按照对象类型进行排序,这些类型要么在总体数量上增长最多(在 对象(差异) 列中单击更改链接),要么在总体堆大小上增长最多(在 堆大小(差异) 列中单击更改链接)。

  • 若要查看仅所选快照的详细信息,请单击非更改链接。

    报表显示在单独的窗口中。

托管类型报告

选择内存使用情况摘要表中 对象(差异) 单元格的当前链接。

托管类型报表的屏幕截图。托管类型报表

备注

对于 .NET 代码,View Details 图标(位于对象类型列中的实例图标 DBG_MMA_InstancesIcon)仅当使用 集成调试器的内存使用情况工具 或打开一个堆栈快照并选择调试托管内存 时才可用。

顶部窗格会显示快照中类型的计数和大小,包括由类型引用的所有对象的大小(非独占大小)。

底部窗格中的“根的路径”树显示引用上部窗格中选择的类型的对象。 .NET垃圾回收器仅在最后一个引用它的类型被释放后才会清理对象的内存。 有关使用“根的路径”树的详细信息,请参阅分析根的热路径。

托管类型报表的屏幕截图。托管类型报表

备注

对于 .NET 代码,查看实例 图标(对象类型列中的实例图标)仅在使用 调试器集成的内存使用工具或在打开 堆快照并选择 调试托管内存 时可用。

顶部窗格会显示快照中类型的计数和大小,包括由类型引用的所有对象的大小(非独占大小)。

底部窗格中的“根的路径”树显示引用上部窗格中选择的类型的对象。 .NET垃圾回收器仅在最后一个引用它的类型被释放后才会清理对象的内存。 有关使用“根的路径”树的详细信息,请参阅分析根的热路径。

“引用的类型”树显示上部窗格中选择的类型所持有的引用。

引用对象报表的屏幕截图。

“引用的类型”树显示上部窗格中选择的类型所持有的引用。

引用对象报表的屏幕截图。

若要在上窗格中显示所选类型的实例,请单击对象类型旁边的 “视图详细信息 ”图标。

内存使用情况工具中实例视图的屏幕截图。内存使用情况工具中的实例视图

“实例”视图显示上部窗格的快照中选定对象的实例。 “根的路径”和“引用的对象”窗格显示引用所选实例的对象以及所选实例引用的类型。 当调试器在拍摄快照的点停止时,可将鼠标悬停在“值”单元格上方,从而在工具提示中显示对象的值。

若要在上窗格中显示所选类型的实例,请单击对象类型旁边的 视图实例 图标。

内存使用情况工具中实例视图的屏幕截图。内存使用情况工具中的实例视图

“实例”视图显示上部窗格的快照中选定对象的实例。 “根的路径”和“引用的对象”窗格显示引用所选实例的对象以及所选实例引用的类型。 当调试器在拍摄快照的点停止时,可将鼠标悬停在“值”单元格上方,从而在工具提示中显示对象的值。

本机类型报告

在 诊断工具 窗口的内存使用情况摘要表中,选择 分配(差异) 或 堆大小(差异) 单元格的当前链接。

本地类型视图的屏幕截图。

本地类型视图的屏幕截图。

类型视图 显示快照中类型的数量和大小。

  • 选择所选类型旁边的 “视图详细信息 ”图标,以显示有关快照中所选类型对象的信息。

    实例 视图显示所选类型的每个实例。 选择实例将显示调用堆栈,该堆栈导致在 分配调用堆栈 窗格中创建实例。 (此信息仅在调试时可用。

    “实例”视图和“分配调用堆栈”窗格的屏幕截图。

  • 选择所选类型旁边的 视图实例 图标,以显示有关快照中所选类型对象的信息。

    实例 视图显示所选类型的每个实例。 选择实例将显示调用堆栈,该堆栈导致在 分配调用堆栈 窗格中创建实例。 (此信息仅在调试时可用。

    “实例”视图和“分配调用堆栈”窗格的屏幕截图。

  • 选择 堆栈 以查看所选类型的分配堆栈。

    堆栈视图的屏幕截图。

  • 选择 堆栈 以查看所选类型的分配堆栈。

    堆栈视图的屏幕截图。

内存使用情况见解

对于托管内存,内存分析工具还提供多个功能强大的内置自动见解。 选择托管类型报表中的“见解” 选项卡,并显示适用的自动见解,例如 重复字符串、稀疏数组,以及 事件处理程序泄漏。

内存使用情况工具中见解视图的屏幕截图。内存使用情况见解

内存使用情况工具中见解视图的屏幕截图。内存使用情况见解

“重复字符串”部分显示了在堆上多次分配的字符串列表。 此外,本部分显示总浪费的内存,即字符串大小的(实例数 - 1) 倍。

稀疏数组 部分显示主要填充零个元素的数组,在性能和内存使用方面可能效率低下。 内存分析工具将自动检测这些数组,并显示由于这些零值而浪费多少内存。

Event Handler Leaks 节在 Visual Studio 2022 版本 17.9 预览版 1 中提供,显示当一个对象订阅另一个对象的事件时可能发生的潜在内存泄漏。 如果事件的发布者比订阅者存活得更久,那么即使没有对订阅者的其他引用,订阅者仍然保持活动状态。 这可能会导致内存泄漏,其中未使用的内存未正确释放,导致应用程序随着时间的推移使用越来越多的内存。

某些类型已知有字段可以读取,以确定它们所占用的本机内存大小。 Insights 选项卡显示对象图中的假本机内存节点,这些节点由其父对象保留,以便 UI 能够识别它们并显示其大小和引用图。

内存使用情况工具中本机见解视图的屏幕截图。内存使用情况工具中的本机见解视图

更改(差异)报告

  • 选择 诊断工具 窗口中 内存使用情况 选项卡摘要表中的更改链接。

    内存使用情况摘要表的屏幕截图,其中快照单元格中突出显示了更改链接。

  • 在托管或本机报告的“比较对象”列表中选择快照。

    “内存使用情况”报表中“与”比较“下拉列表的屏幕截图,其中显示了用于比较的可用快照。

    “内存使用情况”报表中“与”比较“下拉列表的屏幕截图,其中显示了用于比较的可用快照。

更改报告会向基本报告添加一些列(标记为“(差异)”),显示基本快照值与比较快照之间的差异。 下面是本机类型视图差异报告可能会采用的外观:

本地类型差异视图的屏幕截图。本地类型差异视图

本地类型差异视图的屏幕截图。本地类型差异视图

顶部窗格会显示快照中类型的计数和大小,包括由类型引用的所有对象的大小(非独占大小)。

博客和视频

在调试过程中分析 CPU 和内存

Visual C++ 博客:Visual C++ 2015 中的内存分析

后续步骤

在本教程中,你已了解如何在调试时收集和分析内存使用情况数据。 下面是一些建议的后续步骤:

  • 若要分析发布版本中的内存使用情况,请参阅 性能探查器中的“分析内存使用情况”。
  • 若要了解使用分析工具优化代码的一般方法,请参阅 案例研究:优化代码的初学者指南。
  • 若要获取 AI 驱动的分析指导,请参阅使用 GitHub Copilot Profiler Agent 对应用进行分析
  • 有关所有分析工具的概述,请参阅 分析工具初探。