在 Windows 应用开发中,出现 CPU 占用高、内存泄漏等的问题,该如何分析?
产品 / 插件:实时音视频 / 实时语音 / 超低延迟直播
平台 / 框架:Windows
更新时间:2023-12-21 12:08
在 Windows 应用开发中,遇到 CPU 占用高、内存泄漏,需要对应用程序进行调优、性能分析等,以下介绍两种性能分析工具,开发者可以根据业务场景选择。
VS 性能分析工具
以下仅介绍 VS 自带的性能分析工具入门的使用,开发者如有兴趣,可自行去了解更多功能的使用说明。
Visual Studio 自带性能分析工具,可以直接对在 VS 中执行的项目进行分析,也可以追踪生成的可执行文件(例如 pdb 文件),两者的操作在执行分析时有一定的区别,其余都相同。
不同版本的 VS 可能有所差别,但操作步骤大致相同,下文以 Visual Studio 2015 为例。
执行性能分析,并生成分析报告。在菜单栏,选择 “调试 > 性能探查器”,或使用快捷键
Alt + F2
,如下图所示:弹出如下对话框:
选择分析现有项目、其它项目、或其它可执行文件。以 ZegoLiveRoomTopics 示例专题 Demo 为例,选择现有项目,点击 “开始” 启动。
CPU 性能分析
在如下对话框中,选择 “CPU 采样(建议)”,点击 “完成”。
会自动弹出示例 Demo,如图:
以推流功能为例,进行分析。
点击左侧的 “推流”。
再点击 “初始化 SDK”,输入房间 roomID,登录房间。
输入流 streamID,开始推流。
此时,关闭程序,等待生成分析报告。最终报告如下:
点击中间的 “热路径”,按照函数名筛选。
点击 “调用关系树”,可查看整个流程。
独占样本数:指该函数中不包含子函数的执行时间。
非独占样本数:指包含子函数执行时间的总执行时间。
下图为从初始化开始到推流、主要占用 CPU 的函数。其中,AVE 为 ZegoLiveRoom.dll 的内部方法,需要导入符号文件。
从上图可以看出,此次推流过程中的 CPU 消耗,除主线程外,还有 SDK 的编解线程和其他线程。
内存分析
选择 “调试 > 窗口 > 显示诊断工具”,勾选
内存使用率
,即可看到内存运行状态。以推流功能为例。在初始化前,先第一次截取快照 1;推流成功后,截取快照 2。
可以看出,推流成功后,内存增加超过了 20 MB。
点击快照 2 的红色箭头,可以查看详细的内存增长对比。
可以看到,主要的内存增长是在 unsigned char[] 和 void 对象上。由此可以推测,主要是音视频数据模块的申请造成的内存增长。
右上角,切换
视图模式
为 “堆栈视图”,可以查看内存增长的具体触发信息。可以看出,主要是 “外部帧” 引起的内存增长。
点击 “外部帧”,展开详细信息。
可以看到,内存增长主要来自 ZegoLiveRoom.dll,与上文分析的 CPU 增长原因一致。
使用 Process Explorer 分析 CPU 占用率
Process Explorer 是一款由微软提供的免费工具,可以很方便地查看某个进程下各个线程的 CPU 占用率,进行性能分析。
打开 Process Explorer,查看各个进程的资源情况。
可以看到,zegoLiveRoomWrapper.exe 的 CPU 占用率是 3.52%。
在该进程上右键,选择 “Properties...”,再点击切换到 “Threads” 页签,查看具体的线程占用信息。
可以看到,TID 为 27092 的线程占用 CPU 最高。
选择该线程,点击右下角的 “Stack“,可以查看该线程此时的运行堆栈。
可以看到,此时主要是外部采集线程在运行推屏幕数据。
使用 UMDH 定位内存泄漏
UMDH (User-Mode Dump Heap,用户模式转储堆) 是一款轻量级的内存泄漏分析工具,用于监视 Windows 程序的内存使用情况。
UMDH 是 Debugging Tools for Windows 里面的一个工具,主要通过分析比较进程的 Heap Stacktrace 信息来发现内存泄露。
设置环境变量。
打开 “控制面板 > 高级系统设置 > 环境变量”,将 Debugging Tools for Windows 的安装路径(例如:“C:\Program Files (x86)\Windows Kits\10\Debuggers\x64”)添加到系统的 PATH 环境变量中。
设置
_NT_SYMBOL_PATH
系统符号路径。set _NT_SYMBOL_PATH=c:\mysymbols;srv*c:\mycache*https://msdl.microsoft.com/download/symbols
在 Windows 上启动需要监控的应用程序。
生成堆快照。
打开终端,执行命令
umdh -p:PID -f:filename1.txt
。- PID 是您的应用程序的进程 ID。
- filename1.txt 是您保存堆快照后的文件名。
程序运行一段时间后,再次生成一个堆快照,执行命令
umdh -p:PID -f:filename2.txt
。
比较两次堆快照。
执行
umdh -d filename1.txt filename2.txt > diff.txt
,UMDH 会自动比较两个快照,并将结果输出在 “diff.txt” 文件中。打开 diff.txt 文件,可以看到内存增长最大的堆栈信息、以及对应泄漏的调用函数。
如果发现内存泄漏与 ZegoExpressEngine SDK 相关,可以保存好 diff.txt 文件,联系 ZEGO 技术支持进一步分析。
更多 UMDH 使用说明,请参考 UMDH 介绍、使用 UMDH 查找用户模式内存泄漏。