PAYATHON 2026

Qt 5.15.18 在 Windows 上调用 availableDevices() 会泄漏吗?

数据阿明

结论

代码中的 QList<QAudioDeviceInfo> devices 是局部变量,回调返回时会离开作用域。不过,仅凭它是栈变量,无法判断相关内存是否会立即归还给操作系统。VLD 报告中的调用栈经过 MMDevAPI.DLL、Windows 音频驱动和 qtaudio_windowsd.dll,最终到达 QAudioDeviceInfo::availableDevices()。这说明分配发生在设备枚举调用路径上。现有材料无法确认这是 Qt 5.15.18 的已知缺陷,也无法仅凭调用栈确定责任在 Qt、Windows 音频组件还是驱动。

先确认报告代表什么

示例每 100ms 枚举一次设备,调用频率较高。VLD 在进程退出时报告仍未释放的分配,值得进一步调查。不过,任务管理器显示的内存增长,无法单独区分持续泄漏、运行库或系统组件缓存,以及进程工作集尚未回落。

报告中的关键调用路径是:

MMDevAPI.DLL
wdmaud.drv
qtaudio_windowsd.dll
QAudioDeviceFactory::availableDevices()
QAudioDeviceInfo::availableDevices()

这条路径比单看内存曲线更有助于定位问题,但不能据此断定问题出在 Qt 实现内部。报告使用的是带 d 后缀的 Qt 调试库。建议再用 Release 构建和相同的调用频率复现,看看结果是否一致。

建议的排查与规避步骤

  1. 降低枚举频率。如果只是检测设备是否存在,通常不需要每 100ms 查询一次。按实际需求将间隔延长到数秒或更久,并记录调用次数和进程内存,观察内存增长是否仍与调用次数稳定相关。
  2. 缩小复现范围。暂时移除 deviceName() 输出和界面代码,只保留定时调用及结果销毁,然后分别测试一次调用和重复调用,以区分设备枚举与其他回调逻辑的影响。
  3. 比较构建和运行环境。在同一台机器上比较 Debug 和 Release,并记录 Qt Multimedia 的具体构建、Windows 版本及音频设备驱动。条件允许时,可用较新的 Qt 5.15 补丁构建或 Qt 6 做对照;是否已修复需要经过实际验证。
  4. 避免高频轮询。如果业务只需在设备变化时更新状态,可以考虑使用目标平台提供的设备变更通知。具体接口取决于应用使用的 Qt 版本和 Windows 音频方案。仍需轮询时,可以降低频率,只在业务需要时重新枚举。
  5. 保留可复核的证据。用相同的运行时长和调用次数重复测试,分别记录 VLD 报告和内存曲线。如果最小复现仍能稳定增长,可附上 Qt 构建信息、Windows 版本、驱动信息和精简后的调用栈,以便进一步核查 Qt Multimedia Windows 后端或对应的系统组件。

对象管理说明

devices 和循环中的 device 都是局部值对象,离开作用域时会正常析构。当前代码没有显示出需要手动释放这些对象的迹象,也不应对它们调用 delete。w 由 timer 的父子关系管理;示例又在事件循环结束后显式执行 delete w。可以让父对象管理它的生命周期,或改用栈对象。这个写法与报告中指向设备枚举路径的分配栈并不吻合。

在获得跨版本对照结果或 Qt、Windows 组件的确认前,建议先降低枚举频率,并通过最小复现继续验证。目前还不能确定这是已知缺陷,也不能断言某个版本已经修复。

备注:内容仅供参考。