测量 Visual Studio 中的内存使用情况(C#、Visual Basic、C++、F#)
使用调试器集成的 内存使用情况 诊断工具进行调试时,查找内存泄漏和低效内存。 通过内存使用率工具可以拍摄一个或多个托管和本机内存堆的快照,帮助理解对象类型的内存使用率影响。 还可以在不附加调试器的情况下或通过面向正在运行的应用来分析内存使用情况。 有关详细信息,请参阅在发行版本或调试版本上运行分析工具。 有关根据需要选择最佳内存分析工具的信息,请参阅 选择内存分析工具。
尽管可以随时在 内存使用情况 工具中收集内存快照,但可以使用 Visual Studio 调试器来控制应用程序在调查性能问题时的执行方式。 断点设置、步进、全部中断和其他调试器操作可以帮助将性能调查集中在最相关的代码路径上。 在应用程序运行时执行这些操作可以消除你不感兴趣的代码中的干扰,并能显著减少诊断问题所需的时间。
重要
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)
收集内存使用情况数据
打开要在 Visual Studio 中调试的项目,并在要开始检查内存使用情况的点在应用中设置断点。
如果你有一个怀疑内存问题的区域,请设置内存问题发生前的第一个断点。
提示
由于当应用程序频繁分配和释放内存时,要捕获您感兴趣的操作的内存配置文件可能比较困难,因此请在操作的开始和结束时设置断点(或逐步执行操作)以查找内存更改的确切点。
在要分析的函数或代码区域的末尾设置第二个断点(或在出现可疑内存问题后)。
诊断工具 窗口将自动显示,除非你已将其关闭。 若要再次打开窗口,请单击 调试>Windows>显示诊断工具。
使用工具栏上的 “选择工具” 设置,选择 内存使用情况。
单击 调试/开始调试(或单击工具栏上的 开始,或按 F5)。
应用完成加载后,将显示诊断工具的“摘要”视图。
备注
由于收集内存数据可能会影响本机或混合模式应用的调试性能,因此默认禁用内存快照。 若要在本机或混合模式应用中启用快照,请启动调试会话(快捷键:F5)。 出现“诊断工具”窗口时,选择“内存使用情况”选项卡,然后选择 堆分析。
停止(快捷键:Shift+F5)并重启调试。
备注
由于收集内存数据可能会影响本机或混合模式应用的调试性能,因此默认禁用内存快照。 若要在本机或混合模式应用中启用快照,请启动调试会话(快捷键:F5)。 出现“诊断工具”窗口时,选择“内存使用情况”选项卡,然后选择 堆分析。
停止(快捷键:Shift+F5)并重启调试。
若要在调试会话开始时拍摄快照,请选择 在 内存使用情况 摘要工具栏上拍摄快照。 (在此处设置断点可能也会有所帮助。)
提示
若要创建内存比较基线,请考虑在调试会话开始时创建快照。
运行会触发第一个断点的方案。
当调试器在第一个断点暂停时,请选择 在 内存使用情况 摘要工具栏上拍摄快照。
按 F5 将应用运行到第二个断点。
现在,拍摄另一个快照。
此时,可以开始分析数据。
如果在收集或显示数据时遇到问题,请参阅 排查分析错误并修复的问题。
分析内存使用情况数据
“内存使用情况摘要”表中的行会列出在调试会话期间拍摄的快照,并提供指向更详细视图的链接。
列的名称取决于在项目属性中选择的调试模式:.NET、本机或混合(.NET 和本机)。
对象(Diff)(.NET)或 分配(Diff)(C++)列显示在拍摄快照时 .NET 或本地内存中对象的数量。
“堆大小(差异)”列显示 .NET 和本机堆中的字节数
当您创建多个快照后,摘要表的单元格将显示当前行快照与上一快照相比的数值变化。
若要分析内存使用情况,请单击其中一个链接,打开内存使用情况的详细报告:
- 若要查看当前快照与上一快照之间的差异的详细信息,请选择箭头左侧的更改链接(
)。 红色箭头表示内存使用量增加,绿色箭头表示减少。
提示
为了帮助更快识别内存问题,差异报告按照对象类型进行排序,这些类型要么在总体数量上增长最多(在 对象(差异) 列中单击更改链接),要么在总体堆大小上增长最多(在 堆大小(差异) 列中单击更改链接)。
若要查看仅所选快照的详细信息,请单击非更改链接。
报表显示在单独的窗口中。
托管类型报告
选择内存使用情况摘要表中 对象(差异) 单元格的当前链接。
备注
对于 .NET 代码,视图实例 图标()仅在使用 调试器集成的内存使用情况工具 或打开 堆快照 并选择 调试托管内存时可用。
顶部窗格会显示快照中类型的计数和大小,包括由类型引用的所有对象的大小(非独占大小)。
底部窗格中的“根的路径”树显示引用上部窗格中选择的类型的对象。 仅当引用对象的最后一个类型已发布时,.NET 垃圾回收器才会清理对象的内存。 有关使用“根的路径”树的详细信息,请参阅分析根的热路径。
顶部窗格会显示快照中类型的计数和大小,包括由类型引用的所有对象的大小(非独占大小)。
底部窗格中的“根的路径”树显示引用上部窗格中选择的类型的对象。 仅当引用对象的最后一个类型已发布时,.NET 垃圾回收器才会清理对象的内存。
“引用的类型”树显示上部窗格中选择的类型所持有的引用。
“引用的类型”树显示上部窗格中选择的类型所持有的引用。
若要在上窗格中显示所选类型的实例,请单击对象类型旁边的 视图实例 图标。
“实例”视图显示上部窗格的快照中选定对象的实例。 “根的路径”和“引用的对象”窗格显示引用所选实例的对象以及所选实例引用的类型。 当调试器在拍摄快照的点停止时,可将鼠标悬停在“值”单元格上方,从而在工具提示中显示对象的值。
实例 视图在上窗格中显示快照中所选对象的实例。 “根的路径”和“引用的对象”窗格显示引用所选实例的对象以及所选实例引用的类型。 当调试器在拍摄快照的点停止时,可将鼠标悬停在“值”单元格上方,从而在工具提示中显示对象的值。
本机类型报告
在 诊断工具 窗口的内存使用情况摘要表中,选择 分配(差异) 或 堆大小(差异) 单元格的当前链接。
类型视图 显示快照中类型的数量和大小。
选择实例图标(
)以显示有关快照中所选类型的对象的信息。
实例 视图显示所选类型的每个实例。 选择实例将显示调用堆栈,该堆栈导致在 分配调用堆栈 窗格中创建实例。
在 视图模式 列表中选择 堆栈视图,以查看所选类型的分配堆栈。
内存使用情况见解
对于托管内存,内存分析工具还提供多个功能强大的内置自动见解。 选择托管类型报表中的“见解” 选项卡,并显示适用的自动见解,例如 重复字符串、稀疏数组,以及 事件处理程序泄漏。
“重复字符串”部分显示了在堆上多次分配的字符串列表。 此外,本部分显示总浪费的内存,即字符串大小的(实例数 - 1) 倍。
稀疏数组 部分显示主要填充零个元素的数组,在性能和内存使用方面可能效率低下。 内存分析工具将自动检测这些数组,并显示由于这些零值而浪费多少内存。
Visual Studio 2022 版本 17.9 预览版 1 中提供的 事件处理程序泄漏 部分显示一个对象订阅另一个对象的事件时可能发生的潜在内存泄漏。 如果事件发布者的生存期超过了订阅者的生存期,即使没有对订阅者的其他引用,订阅者仍会保持活动状态。 这可能会导致内存泄漏,其中未使用的内存未正确释放,导致应用程序随着时间的推移使用越来越多的内存。
某些类型已知有字段可以读取,以确定它们所占用的本机内存大小。 Insights 选项卡显示对象图中的假本机内存节点,这些节点由其父对象保留,以便 UI 能够识别它们并显示其大小和引用图。
更改(差异)报告
选择 诊断工具 窗口中 内存使用情况 选项卡摘要表中的更改链接。
在托管或本机报告的“比较对象”列表中选择快照。
更改报告会向基本报告添加一些列(标记为“(差异)”),显示基本快照值与比较快照之间的差异。 下面是本机类型视图差异报告可能会采用的外观:
顶部窗格会显示快照中类型的计数和大小,包括由类型引用的所有对象的大小(非独占大小)。
博客和视频
Visual C++ 博客:Visual C++ 2015 中的内存分析
后续步骤
本教程介绍了如何收集和分析内存使用情况数据。 如果你已经完成了性能分析器 的教程,你可能会想了解如何使用分析工具来优化代码的一般方法。
在本教程中,你已了解如何在调试时收集和分析内存使用情况数据。 你可能想要详细了解如何使用性能探查器分析发布版本中的内存使用情况。