Qt 内存泄漏排查工具配置指南(Windows / HarmonyOS)

适用工程:SamplePad(Qt5/Qt6 + CMake,Windows 桌面 + HarmonyOS 平板)
编写日期:2026-11-13


1. 结论先行

Valgrind 在 Windows 上不可用。 它依赖 Linux/macOS 的 ELF 与 ptrace 机制,没有 Windows 移植版本,因此 Qt Creator 的 Valgrind 分析面板在 Windows 下为不可用状态,这不是配置问题。

Windows + Qt 环境下实际可用的方案有三套:

方案定位是否改构建/代码推荐度
HeobQt 官方维护的 Windows 内存检查器,Qt Creator 原生集成否★★★★★ 首选
AddressSanitizer (ASan)编译器级检测,速度快、报告带完整分配栈需加编译/链接选项★★★★☆ 精确定位
CRT 泄漏检测MSVC 运行时自带,零配置需在 main 加 3 行★★★☆☆ 粗筛

如果确实需要 Valgrind 本体,只能在 Linux 环境(或远程 Linux 设备)上运行。


2. 工具对比

能力HeobASanCRTValgrind (Linux)
内存泄漏✅✅✅(无栈)✅
堆越界写✅✅❌✅
未初始化读❌✅❌✅
释放后使用 (UAF)部分✅❌✅
报告含调用栈✅✅❌✅
运行开销中低(约 2x)无高(10~30x)
图形界面✅❌(控制台)❌✅(Qt Creator)
平台WindowsWin/Linux/macOSWindowsLinux/macOS

3. Heob 配置(首选方案)

3.1 安装

  1. 获取 heob:Qt 官方仓库 https://github.com/QUItCoding/heob,或 Qt Creator 安装包内自带。
  2. 解压后得到 heob.exe(32/64 位按工程匹配,本工程为 64 位)。

3.2 Qt Creator 配置

  1. 打开 Tools → Options → Analyzer → Heob,填写 heob.exe 的完整路径。
  2. 左侧边栏切换到 Analyze(分析) 模式 → 选择 Heob。
  3. 顶部勾选关键选项:
    • Leak detection:检测内存泄漏
    • Stack trace:记录分配调用栈(定位到文件行号,必开)
    • Extra image checks:检测堆越界写
  4. 点击绿色三角启动,程序运行期间正常操作,退出后在 Issues 面板查看结果。

3.3 结果判读

  • 按「泄漏字节数」降序排列,优先看 Top 10。
  • 展开条目可看到完整分配栈,直接定位到 new 所在行。
  • 重点关注项目中的高频创建对象:ToastWidget、CardItemWidget、各类 *PopupWidget、*MaskWidget。

3.4 局限

  • 不检测未初始化读。
  • 部分 Qt 内部单例会被报告为「泄漏」,需人工排除(不影响判读)。

4. AddressSanitizer 配置

4.1 CMake 配置

仅 Debug 构建开启,Release 必须关闭(性能影响约 2 倍)。

# 仅 MSVC + Debug 生效
if(MSVC AND CMAKE_BUILD_TYPE STREQUAL "Debug")
    add_compile_options(/fsanitize=address /Zi)
    add_link_options(/INFERASANLIBS)
endif()

环境要求:Visual Studio 2019 16.9+ 或 VS 2022。

4.2 首次运行注意事项

MSVC 不会自动部署 ASan 运行时,需要把以下 DLL 拷贝到可执行文件同目录:

clang_rt.asan_dbg_dynamic-x86_64.dll

路径通常在 C:\Program Files\Microsoft Visual Studio\2022\<Edition>\VC\Tools\MSVC\<ver>\bin\Hostx64\x64\ 下。

否则启动时直接报缺少 DLL。

4.3 输出解读

程序退出时在控制台/应用程序输出窗口打印:

Direct leak of 96 byte(s) in 1 object(s) allocated from:
    #0 operator new
    #1 ToastWidget::ToastWidget(...)  ToastWidget.cpp:31
    #2 ToastWidget::instance()        ToastWidget.cpp:55
  • Direct leak:对象本身未被释放
  • Indirect leak:被泄漏对象内部持有的子对象(跟进 Direct 即可)
  • #1、#2 即分配时的调用栈,直接对应源码行

4.4 Qt 误报抑制

Qt 自身的全局单例、字体缓存、平台插件常被报为泄漏。通过抑制文件过滤:

set ASAN_OPTIONS=detect_leaks=1:suppressions=qt.supp

qt.supp 内容示例:

leak:libQt5Core
leak:libQt5Gui
leak:libQt6Core
leak:libQt6Gui
leak:QFontDatabase
leak:QFactoryLoader

判读原则:只关注调用栈里出现工程自身源码的条目。


5. CRT 泄漏检测(快速粗筛)

5.1 配置

在 main.cpp 中:

#if defined(_MSC_VER) && defined(_DEBUG)
#  include <crtdbg.h>
#endif

int main(int argc, char *argv[])
{
#if defined(_MSC_VER) && defined(_DEBUG)
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    // 定位到具体分配点:把报告中的编号填入下一行并取消注释
    // _CrtSetBreakAlloc(1234);
#endif

    // ... 原有代码
}

5.2 输出

程序退出时输出窗口打印:

Detected memory leaks!
Dumping objects ->
{1234} normal block at 0x000001F2A3B4C5D0, 96 bytes long.

5.3 定位技巧

把 {1234} 中的编号填入 _CrtSetBreakAlloc(1234),重新以调试方式运行,程序会在该次分配处直接断点停下,从调用栈即可看到确切位置。

优点:零依赖、零构建改动(仅 3 行代码)。
缺点:无调用栈、无越界检测,适合快速判断「有没有泄漏」,不适合定位。


6. Valgrind 本体使用(仅 Linux)

6.1 命令行方式

valgrind --leak-check=full \
         --show-leak-kinds=all \
         --track-origins=yes \
         --log-file=valgrind.log \
         ./SamplePad

常用参数:

参数作用
--leak-check=full输出每条泄漏的完整栈
--show-leak-kinds=all包含 definitely/indirect/possible
--track-origins=yes追踪未初始化值的来源(必开,慢但关键)
--log-file=输出到文件,避免刷屏
--num-callers=30栈深度

6.2 Qt Creator 集成(Linux)

Configure Project → 选择 Linux Kit → 左侧 Analyze → Valgrind Memory Analyzer。前提是目标机器已安装 valgrind(sudo apt install valgrind)。

6.3 WSL 的限制

WSL2 可以运行 Valgrind,但无法运行 Qt GUI 程序(缺少可用的图形平台插件链路)。WSL 仅适合运行不依赖界面的纯逻辑单元测试。


7. HarmonyOS 平板场景

Valgrind、Heob、ASan 均无法直接用于鸿蒙真机排查,原因是目标平台为 aarch64-unknown-linux-ohos,工具链与运行时均不匹配。

实际可用的排查手段:

  1. 析构日志法(最直接)
    在可疑类的析构函数中打 hilog:

    ToastWidget::~ToastWidget()
    {
        OH_LOG_Print(LOG_APP, LOG_INFO, 0x0000, "LeakCheck", "~ToastWidget");
        delete ui;
    }
    

    反复操作弹窗 50 次以上,观察日志中构造次数与析构次数是否平衡。

  2. 对象计数法
    在构造/析构里对静态计数器 +1/-1,定时打印当前存活数量。数字只增不减即为泄漏。

  3. 常驻内存观察
    长时间运行(数小时)后用 hdc shell hidumper -s 1901 观察进程内存曲线是否单调上涨。

  4. 对照法
    先在 Windows 桌面版用 Heob 定位问题代码,再回到鸿蒙验证——同一份 Qt 源码,泄漏点一致。


8. 实战排查顺序建议

① Heob 跑一遍(10 分钟)           → 判断有无泄漏、Top 嫌疑类
② 有明确嫌疑 → ASan 精确定位栈      → 拿到文件:行号
③ 无嫌疑但怀疑泛化问题 → CRT 粗筛   → 快速确认
④ 鸿蒙侧 → 析构日志 + 计数验证修复

判定「修好了」的标准:同一操作重复 N 次,存活对象数回到基线,内存曲线平稳——不是「跑一次没报错」。


9. 常见误报与陷阱

现象原因处理
ASan 报大量 Qt 内部泄漏Qt 全局单例、字体缓存写抑制文件过滤
Heob 报告 QFactoryLoader平台插件加载器常驻忽略
CRT 只报编号无栈运行时机制限制用 _CrtSetBreakAlloc 断点定位
ASan 启动报缺 DLLMSVC 未部署运行时拷贝 clang_rt.asan_dbg_dynamic-x86_64.dll
Release 下 ASan 极慢插桩开销只在 Debug 开启
「泄漏」其实是缓存策略QPixmapCache、字体缓存故意常驻结合业务判断,勿盲目「修」


文档结束

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐