still reachable 不是内存泄漏,而是程序退出时仍有指针可访问该内存;常见于全局/静态变量持有、第三方库缓存等,需结合调用栈与代码意图判断是否需修复。

不算真正意义上的内存泄漏,但需要人工判断是否合理。
still reachable 的本质是“程序退出时仍有指针能访问到这块内存”
Valgrind 把它单独归为一类,不是因为检测失败,而是明确区分了语义:这块内存没被释放,但也没丢——你还能通过全局变量、静态变量、main 函数栈上保存的指针等途径访问它。
- 常见于:Qt 初始化分配的事件循环缓存、glib 的对象系统池、日志模块的全局缓冲区、C++ static std::vector
等 - 关键判断依据:
main返回前是否还持有有效指针;如果没写任何全局new或malloc,却看到大量still reachable,大概率是漏加-g编译选项,导致 Valgrind 无法解析调用栈,把本该归入definitely lost的泄漏误判为still reachable - 它不触发 GC(C/C++ 没 GC),也不影响运行期内存增长趋势——只要 heap_inuse 不持续上涨,就不是运行时泄漏源
什么时候要修,什么时候可忽略
不能只看分类名,得结合上下文和代码意图:
- 若
still reachable来自你写的全局std::map<int std::shared_ptr>></int>且从不清理,那就是设计缺陷,得加清理逻辑 - 若来自第三方库(如
libcurl初始化时的内部缓存),且 Valgrind 输出里有匹配的 suppress 规则,或报告中明确标为suppressed,可忽略 - 若泄漏量固定(比如每次运行都是 4096 bytes in 2 blocks),且与程序逻辑强相关(如单例对象生命周期贯穿全程),基本安全
容易踩的坑:把 still reachable 当成“没问题”直接跳过
真实项目里最麻烦的情况是:某处本该在 atexit() 或析构函数里 free 的资源,因异常路径未执行,结果变成 still reachable —— 表面看是“还拿着”,实际是“该放没放”。
- 检查点:看 Valgrind 报告里的调用栈是否指向你的代码,尤其是构造函数、
init()、main()开头部分 - 验证方法:用
addr2line -e ./your_program 0x12345678把报告中的地址转成源码行号,确认是不是你可控的分配点 - 对比手段:跑两次 Valgrind,一次正常退出,一次用
kill -9强杀,若后者still reachable暴增,说明原本靠优雅退出清理的逻辑失效了
真正要盯死的是 definitely lost 和反复出现的 possibly lost;still reachable 是个提示灯,亮了不报警,但得凑近看清楚照的是什么。











