【C++】019、内存泄漏

一、内存泄漏定义

  • 指程序在动态分配内存后,失去了对该内存块的所有指针引用,导致在程序内存生命周期结束前无法被释放或回收的现象

二、内存泄漏的三大根本原因

1、遗忘释放:

  • 写了new、malloc,但忘了写对应的delete、free,常见于业务逻辑及其复杂的函数中,开发者在return前遗漏了释放内存的代码。

2、异常路径打乱流程:

  • 函数执行过程中抛出了异常,直接跳过了后面的delete语句,导致之前分配的内存无法释放。

3、释放姿势错误:

  • 基类析构函数没有声明为虚函数virtual,当用基类指针指向派生类对象并delete时,派生类的析构函数不会执行,导致派生类自身持有的堆资源随即泄漏。

三、四大常见内存泄漏场景

1、循环中的临时对象:

  • 在while或for循环中,持续的new对象,却忘了在循环末尾delete,是短时间内将内存耗尽(OOM)的最快方式

2、容器中的裸指针:

  • vector中存放了new出来的裸指针,当vector被销毁或清空时,只会释放容器自身空间,不会自动delete这些指针指向的元素。

3、跨模块内存管理:

  • 在一个动态库中(dll、so)new内存,却在另一个模块中delete,(在so库文件中申请内存,却在调用exe文件中对该对象内存进行释放),如果两个模块链接了不同的运行时库,堆管理结构不一致,导致泄漏或崩溃。

4、线程局部存储未清理:

  • 线程结束时,未清理线程局部存储中的堆指针,导致泄漏。

四、内存泄漏监测工具

1、valgrind:

  • 原理是通过跟踪每次内存读写和释放,可以定位到内存泄漏的代码行号,缺点是会让程序运行速度变慢10-50倍。

2、Asan:

  • 通过影子内存(哨兵内存)的技术实时监测,速度快,能够精准捕获堆溢出,栈溢出和内存泄漏。

3、window平台:

  • CRT调试钩子

4、内存钩子(Hook)重载operate new

  • 也就是插桩技术,重载全局operate new和operate delete,实时打印未释放的存活对象。

五、shared_ptr 循环引用导致的逻辑泄漏

  • 如果两个对象互相持有shared_ptr,引用计数永远降不到0,析构函数永远不会调用。

六、预防内存泄漏的工程实战

  • 杜绝裸new、delete

  • 强制使用RAII:使用unique_ptr,shared_ptr, 让堆内存的生命周期绑定到栈对象上。,利用栈的自动析构特性,从根源上消除忘记释放和异常跳过释放的问题。

  • 当需要自定义内存池时,才允许使用 placement new和显示析构。

相关推荐
wangbing112523 分钟前
springboot应用关闭时触发动作
java·spring boot·后端
weixin_460443563 小时前
2026年新修订《网络安全法》实施:Java私有化考试系统如何做好SBOM、漏洞治理与安全升级?
java·开发语言·在线考试系统·企业培训考试系统·宏远培训考试系统·国企培训考试系统·国产化培训系统
海鸥-w6 小时前
什么是AOP
java
Cc.Y7 小时前
Java零基础入门:可变字符串与包装类:StringBuilder、StringBuffer 与 通讯录管理系统实战
java·开发语言·python
paopaokaka_luck7 小时前
基于springboot+vue的智慧家政管理系统(AI问答、 WebSocket实时沟通、ECharts运营分析、订单规则与服务追踪)
java·javascript·spring boot·数据分析·echarts·mybatis
sm_926787057 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
阿森_dev7 小时前
2027 届毕设选题怎么选:30 个 Java 方向选题的实现难度排序
java·开发语言·spring boot·毕业设计·课程设计
by209997 小时前
C++ 多态:同一个基类接口,调用不同的函数
开发语言·c++·经验分享·多态
笔墨登场说说7 小时前
flink bin/start-cluster.sh 帮我做成开机启动
开发语言·python
Sarvartha7 小时前
Lambda 表达式和函数式接口
java·开发语言