
new/delete 不配对是内存泄漏最常见原因
写 C++ 时只要手动用 new 分配了内存,就必须有且仅有一次对应的 delete(或 delete[]);漏掉、多调、提前释放,都会出问题。不是“大概率”会泄漏,而是“一定”会——只要那块内存没被回收,它就一直占着。
典型错误现象:valgrind --leak-check=full ./a.out 报 definitely lost 或 still reachable;程序跑久后 RSS 内存持续上涨,但没明显 crash。
- 用
new分配单个对象 → 必须用delete,不能用delete[] - 用
new[]分配数组 → 必须用delete[],不能用delete(否则析构只调第一个元素,且可能破坏堆元数据) - 别在异常路径里丢掉
delete:比如new后马上抛异常,没来得及delete—— 推荐用 RAII(std::unique_ptr/std::vector)兜底 - 跨 DLL/so 边界传 raw pointer 并在另一侧
delete是危险操作:分配和释放必须用同一套堆管理器(同编译器、同 CRT 版本)
valgrind 能抓到但 ASan 更快更准
valgrind 是老牌工具,但慢(10–30 倍)、不支持某些系统调用、无法检测栈溢出或 UAF;而 AddressSanitizer(ASan)编译期插桩,运行时开销小(~2×),能同时捕获内存泄漏、越界读写、UAF、use-after-return 等问题。
使用场景:本地开发阶段日常检查;CI 中加 ASan 编译选项跑单元测试。
立即学习“C++免费学习笔记(深入)”;
- 编译加
-fsanitize=address -g,链接也要加(Clang/GCC 都支持) - 运行时报错直接带 stack trace 和内存状态(比如
heap-use-after-free),比 valgrind 的 offset 更易定位 - 注意:ASan 默认不报告“未释放内存”(即 leak),需额外加
-fsanitize=address,leak并设置LSAN_OPTIONS=detect_leaks=1 - Windows 下用
Dr. Memory或 VS 自带的 CRT debug heap(_CrtDumpMemoryLeaks()),但体验不如 ASan 流畅
std::shared_ptr 循环引用会让内存永远不释放
用 std::shared_ptr 确实能自动管理生命周期,但它靠引用计数;两个对象互相持有对方的 std::shared_ptr,计数永远不会归零,内存就卡死在那里。
常见于 Observer 模式、树形结构父子节点、回调绑定等场景。
- 看是否真需要共享所有权:多数情况用
std::unique_ptr+ 引用/裸指针观察更安全 - 循环引用处改用
std::weak_ptr打断计数链(比如子节点存父节点的std::weak_ptr,访问前.lock()) - 用
std::enable_shared_from_this时小心:派生类构造函数里调shared_from_this()会 crash(this 尚未被 shared_ptr 管理) - 调试技巧:在关键对象的析构函数里打日志,如果从不触发,基本就是循环引用或忘了 move
自定义 new/delete 容易踩堆管理一致性坑
重载类级别的 operator new / operator delete 是高级操作,常用于内存池、对齐控制或调试统计;但一旦用了,就必须成对实现所有变体(nothrow、size_t 版本、数组版本),否则行为不可控。
错误现象:程序随机 crash、malloc(): corrupted top size、或 delete 时跳进默认 operator delete 导致 double-free。
- 类内声明
void* operator new(size_t)→ 必须同时声明void operator delete(void*)(否则 delete 会调全局版本) - 若重载了
operator new[],也必须重载operator delete[];否则new[]分配的内存会被operator delete释放(UB) - 不要在重载的
new里 throw(除非你处理了 nothrow 场景);也不要在delete里抛异常(C++ 标准禁止) - 更稳妥的做法:用
std::pmr::polymorphic_allocator(C++17)替代全局重载,按 scope 切换内存源,避免污染整个进程
内存泄漏最难缠的地方不在“找不到哪行漏了”,而在“以为自己管好了,其实某个隐式拷贝、某个异常分支、某次跨模块传递,悄悄绕过了你的释放逻辑”。工具只能报现象,根因还得靠对所有权转移路径的清醒判断。








