通过减少内存和磁盘空间的使用来提高应用性能

本指南将演示如何通过两个主要方式提高 Windows 应用程序的性能:

最小化内存使用率

有多种方法可以将 Windows 应用使用的内存最小化,你可以:

  • 减少前台内存使用。
  • 最小化后台工作。
  • 释放后台资源。
  • 避免应用程序内存泄露

为了合理最小化内存使用,首先必须了解:

要分析系统跟踪,建议参考应用跟踪分析以减少内存使用指南。

工作集、动态内存和虚拟分配

应用程序的工作集是当前驻留内存的虚拟地址空间内的页面集,是应用的内存使用情况的一个度量值。

应用程序使用的内存量会影响其运行时性能,以及整个系统的响应能力。 减少内存使用有助于应用降低访问内存相关的 CTU 成本,从而提升性能。 较低的内存使用也能提升系统响应能力和应用整体的用户体验,因为可以避免应用程序发生置换其他内存内容的情况。

由于系统会尝试保留最近访问的内存内容,并且会在必要时将使用过的内容进行缩减或移除,因此可能会导致内存置换。 当用户切换回 shell 或其他应用程序时,如果必要数据未驻留在内存中,则需要从磁盘读取数据。 此过程可能会使用户注意到速度变慢。

应用程序使用的内存有两个关键部分:1)动态内存和 2)文件支持的内存。 文件内存使用量来自应用程序使用的二进制文件和数据文件,例如应用程序使用的数据库。 这通常不会大量占用内存使用量,一般是一个常量。 (数据处理应用程序、代码编译等除外。) 内存使用和泄露情况更多主要来自动态内存。

动态内存对应着应用程序使用内存分配例程分配的虚拟内存。 动态内存与文件映射型的内存不同,文件映射型内存在系统重新启动后仍存在,而动态内存仅存在于应用程序的生存期内。 动态内存是内存使用的常见重要来源,也经常出现内存泄露的情况。

虚拟分配例程 (VirtualAlloc) 独立于用于内存分配的应用程序层例程,负责处理 Windows 应用程序内存分配请求。 虽然应用程序分配的所有内存并非一直都驻留在内存中,但分析此类分配情况可以持续了解应用程序的内存使用情况。

要了解应用程序的内存使用情况并加以改进,建议捕获 VirtualAllocation 跟踪,如下所示。

捕获系统跟踪以分析内存使用情况

记录一段时间内的设备活动称为系统跟踪。系统跟踪会生成一份跟踪文件,可用于生成报表,从而帮助你明确提高应用性能的思路。

可以进行不同时长的跟踪:

  • 短时跟踪可用于捕获应用程序的启动。 包括应用转换到非活动状态时,此时应用程序窗口为最小化状态或已关闭,而应用程序进程仍在运行。
  • 通常持续时间为几分钟的长时跟踪可用于诊断内存泄漏。 如果内存使用持续随时间增加,通常说明存在泄漏qing。

有多个可用于监视内存使用的工具,包括:

本文将重点介绍如何使用 Windows Performance Analyzer。 若要详细了解如何选择用于分析应用程序性能的工具,请参阅 在 Visual Studio 性能探查器、Windows Performance Toolkit 和 PerfView 之间进行选择

捕获跟踪

  1. 管理员模式下打开命令行(PowerShell 或命令提示符)。 (如果未在管理员模式下运行,可能会收到错误代码:0xc5585011,“无法启用分析系统性能的策略。”)

  2. 输入命令:wpr -start VirtualAllocation -filemode

  3. 运行要调查的场景。 (例如启动应用程序。)

  4. 输入命令:wpr -stop Trace.etl

分析系统跟踪

要找到应用的哪些功能分配的内存可以减少,需要分析捕获的系统跟踪。 分析跟踪:

  1. 输入命令 wpa.exe Trace.etl,使用 Windows Performance Analyzer 打开跟踪:

  2. Graph 浏览器中展开内存,右键单击“全部提交”图像,然后选择将图形添加到新分析视图

  3. 单击“设置”c齿轮以打开视图编辑器,选择以下列排列:进程提交类型提交堆栈大小

  4. 单击大小列标题,按降序对结果进行排序。 提交堆栈展示了指向分配内存的代码路径。 这些结果可能有助于了解分配的原因。 按大小排序后,你可以专注于更大比例的分配,了解是否有可优化的空间。

  5. 通过右键单击进程并选择筛选到选择来筛选你感兴趣的一个或多个进程。

  6. 要放大视区中感兴趣的区域,请选择一个区域,右键单击图表,然后选择缩放

  7. 浏览提交堆栈以了解哪些功能已分配内存。 提交堆栈需要 已加载符号。 要加载符号,请从顶部导航菜单栏中选择跟踪>加载符号

    Windows 性能分析器内存跟踪屏幕截图

应用跟踪分析以减少内存使用

在分析分配的内存时,你会发现最小化内存使用方法的线索。

在将跟踪分析应用于更新代码,从而减少内存使用时需要考虑几个方面,包括:

  • 减少前台的内存使用:分析内存跟踪有助于识别前台不必要的内存使用,并更新代码将其减少或删除。

  • 最小化后台工作:系统使用从进程工作集中淘汰页面的策略。 通过使用更少的后台内存,系统可以通过保留较少的应用程序内存常驻来提高效率。 详细了解如何最小化后台工作以优化能耗和电池使用时间,这些方法也可用于最小化后台使用的内存。

  • 释放后台资源:应用程序在运行时可能会创建一些内存缓存,以及创建图形分配以支持其 UI。 这些分配可在应用程序最小化或不可见时释放。 应用程序可以发送低内存通知以释放内存,但更好的策略是在用户未使用应用程序一段时间后,应用处于非活动状态时释放内存。 不同应用程序的未使用时间可以不同,因此非活动使用指标范围可以是几分钟到半小时或更长时间。 应注意平衡内存节省与响应能力。 如果重新生成缓存的成本很高,那么应用程序可以选择在其生存期内保留缓存。

  • 确定应用程序未发生内存泄漏:要检查内存是否泄漏,请先建立稳定状态基准,表示应用程序内存使用已稳定,或者未超出特定值。 可以通过持续使用应用程序或在后台将其保持空闲状态来建立此稳定状态。 使用捕获的跟踪来识别可能发生的内存泄漏时,可以在代码中查找内存分配位置,以及内存在完成任务后的释放方法。 如果内存在应用程序运行时持续增加,可能说明发生了泄漏。 放大跟踪中的内存增加区域,并仔细分析提交堆栈。

高效使用磁盘空间

磁盘占用 是指应用程序在非活动状态下(未执行代码)时的存储大小。 如果应用程序占用了大量磁盘空间,说明有优化空间。

可通过多种方式减少应用的磁盘占用以提高性能:

  • 如果磁盘已满,文件系统则无法再以连续形式存储新内容。 完整磁盘将被分割为片段,而新内容将存储在非连续扇区上。 这会增加磁盘访问该内容的延迟时间。 当内容连续且可按顺序访问时,或使用的 IO 较大时,IO 系统能提供更好的磁盘吞吐量。

  • 磁盘已满会造成更长的 SSD 系统写入延迟。 如果可写入的空单元格不足,写入操作可能会引起“读取-修改-写入”操作,从而降低性能。

  • 磁盘已满可能会影响应用程序更新。 虽然 OS 具有复原能力,能够使系统在可用磁盘空间不足的情况下依旧处于最新版本并保证系统安全,但充足的可用磁盘空间能带来更快更流畅的更新体验。

  • 运行时大量访问大型磁盘占用也会造成内存使用。 这会影响应用程序和系统的响应能力。 此外,如果应用程序运行时磁盘占用较少,也可能造成磁盘空间使用效率过低。

减少磁盘空间或提高使用效率的方法包括:

  • 将“即用即付”原则应用于磁盘占用(仅下载必需内容):应用程序包含了大量功能,但有些并不适用于所有用户。 这可能会造成磁盘占用量大。 通过应用“即用即付”原则,可以要求用户仅下载自己需要的功能,从而在下载应用时占用较小的磁盘空间。 如果用户需要更丰富的功能,可以选择下载其他内容。 除了功能,还可以将“即用即付”原则应用在语言支持上。 应用程序可以默认包含常用语言选项的子集,同时提供其他语言选项,或使用用户系统的位置集作为依赖项。

  • 应用高效的缓存大小:应用程序可以通过磁盘缓存使某些场景下的用户体验更敏捷。 可以为应用程序管理缓存的方式设置策略,基于磁盘容量设置缓存大小的上限,并在磁盘可用空间较小时调整缓存大小。

  • 高效使用资产:应用程序通常包含图像资产,并且可能包含一系列大小的图像以支持不同分辨率。 优化分辨率子集的图像大小、维度、格式和压缩,并利用缩放来支持剩余分辨率,可以显著减少磁盘占用。

  • 寻找二进制优化机会SizeBench等工具帮助应用程序作者发现产生二进制占用的原因和减少已用磁盘空间的机会。

其他资源