Qt内存泄漏排查工具配置指南
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 环境下实际可用的方案有三套:
| 方案 | 定位 | 是否改构建/代码 | 推荐度 |
|---|---|---|---|
| Heob | Qt 官方维护的 Windows 内存检查器,Qt Creator 原生集成 | 否 | ★★★★★ 首选 |
| AddressSanitizer (ASan) | 编译器级检测,速度快、报告带完整分配栈 | 需加编译/链接选项 | ★★★★☆ 精确定位 |
| CRT 泄漏检测 | MSVC 运行时自带,零配置 | 需在 main 加 3 行 | ★★★☆☆ 粗筛 |
如果确实需要 Valgrind 本体,只能在 Linux 环境(或远程 Linux 设备)上运行。
2. 工具对比
| 能力 | Heob | ASan | CRT | Valgrind (Linux) |
|---|---|---|---|---|
| 内存泄漏 | ✅ | ✅ | ✅(无栈) | ✅ |
| 堆越界写 | ✅ | ✅ | ❌ | ✅ |
| 未初始化读 | ❌ | ✅ | ❌ | ✅ |
| 释放后使用 (UAF) | 部分 | ✅ | ❌ | ✅ |
| 报告含调用栈 | ✅ | ✅ | ❌ | ✅ |
| 运行开销 | 中 | 低(约 2x) | 无 | 高(10~30x) |
| 图形界面 | ✅ | ❌(控制台) | ❌ | ✅(Qt Creator) |
| 平台 | Windows | Win/Linux/macOS | Windows | Linux/macOS |
3. Heob 配置(首选方案)
3.1 安装
- 获取 heob:Qt 官方仓库
https://github.com/QUItCoding/heob,或 Qt Creator 安装包内自带。 - 解压后得到
heob.exe(32/64 位按工程匹配,本工程为 64 位)。
3.2 Qt Creator 配置
- 打开 Tools → Options → Analyzer → Heob,填写
heob.exe的完整路径。 - 左侧边栏切换到 Analyze(分析) 模式 → 选择 Heob。
- 顶部勾选关键选项:
- Leak detection:检测内存泄漏
- Stack trace:记录分配调用栈(定位到文件行号,必开)
- Extra image checks:检测堆越界写
- 点击绿色三角启动,程序运行期间正常操作,退出后在 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,工具链与运行时均不匹配。
实际可用的排查手段:
-
析构日志法(最直接)
在可疑类的析构函数中打 hilog:ToastWidget::~ToastWidget() { OH_LOG_Print(LOG_APP, LOG_INFO, 0x0000, "LeakCheck", "~ToastWidget"); delete ui; }反复操作弹窗 50 次以上,观察日志中构造次数与析构次数是否平衡。
-
对象计数法
在构造/析构里对静态计数器+1/-1,定时打印当前存活数量。数字只增不减即为泄漏。 -
常驻内存观察
长时间运行(数小时)后用hdc shell hidumper -s 1901观察进程内存曲线是否单调上涨。 -
对照法
先在 Windows 桌面版用 Heob 定位问题代码,再回到鸿蒙验证——同一份 Qt 源码,泄漏点一致。
8. 实战排查顺序建议
① Heob 跑一遍(10 分钟) → 判断有无泄漏、Top 嫌疑类
② 有明确嫌疑 → ASan 精确定位栈 → 拿到文件:行号
③ 无嫌疑但怀疑泛化问题 → CRT 粗筛 → 快速确认
④ 鸿蒙侧 → 析构日志 + 计数验证修复
判定「修好了」的标准:同一操作重复 N 次,存活对象数回到基线,内存曲线平稳——不是「跑一次没报错」。
9. 常见误报与陷阱
| 现象 | 原因 | 处理 |
|---|---|---|
| ASan 报大量 Qt 内部泄漏 | Qt 全局单例、字体缓存 | 写抑制文件过滤 |
Heob 报告 QFactoryLoader | 平台插件加载器常驻 | 忽略 |
| CRT 只报编号无栈 | 运行时机制限制 | 用 _CrtSetBreakAlloc 断点定位 |
| ASan 启动报缺 DLL | MSVC 未部署运行时 | 拷贝 clang_rt.asan_dbg_dynamic-x86_64.dll |
| Release 下 ASan 极慢 | 插桩开销 | 只在 Debug 开启 |
| 「泄漏」其实是缓存策略 | QPixmapCache、字体缓存故意常驻 | 结合业务判断,勿盲目「修」 |
文档结束
更多推荐

所有评论(0)