当前位置: 首页 > news >正文

C++ 内存泄漏

1. 内存泄漏:

在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。

内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

 

C/C++由于灵活、高效的优点一直以来都是主流的程序设计语言之一,但是其没有垃圾回收机制,内存的分配与释放均由程序员自己管理,当由于疏忽或错误造成程序未能释放不再使用的内存时就会造成内存泄漏。

在大型、复杂的应用程序中,内存泄漏往往是最常见的问题,因而及时解决内存泄漏非常必要,tMemMonitor (TMM)作为一个专业、准确、易用的内存泄漏分析工具,可以帮助C/C++程序员迅速地解决内存泄漏这个令人头疼的问题。

 

2. 内存泄漏后果:

只发生一次的小的内存泄漏可能不会被注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种征兆:从性能不良(并且逐渐降低)到内存完全用尽。

更糟的是,泄漏的程序可能会用掉太多内存,以致另一个程序失败,而使用户无从查找问题的真正根源。 此外,即使无害的内存泄漏也可能是其他问题的征兆。

内存泄漏会因为减少可用内存的数量从而降低计算机的性能。

内存泄漏也会导致较严重的后果:

  • 程序运行后置之不理,并且随着时间的流失消耗越来越多的内存(比如服务器上的后台任务,尤其是嵌入式系统中的后台任务,这些任务可能被运行后很多年内都置之不理);
  • 新的内存被频繁地分配,比如当显示电脑游戏或动画视频画面时;
  • 程序能够请求未被释放的内存(比如共享内存),甚至是在程序终止的时候;
  • 泄漏在操作系统内部发生;
  • 泄漏在系统关键驱动中发生;
  • 内存非常有限,比如在嵌入式系统或便携设备中;
  • 当运行于一个终止时内存并不自动释放的操作系统(比如AmigaOS)之上,而且一旦丢失只能通过重启来恢复。

 

3. 内存泄漏的几种情况:

 

1). 在类的构造函数和析构函数中没有匹配的调用newdelete函数

两种情况下会出现这种内存泄露:

一是在堆里创建了对象占用了内存,但是没有显示地释放对象占用的内存;

二是在类的构造函数中动态的分配了内存,但是在析构函数中没有释放内存或者没有正确的释放内存;

 

2). 没有正确的清除嵌套对象的指针

 

3). 在释放对象数组时在delete中没有使用方括号

方括号是告诉编译器这个指针指向的是一个对象数组,同时也告诉编译器正确的对象地址值病调用对象的析构函数,如果没有方括号,那么这个指针就被默认为只指向一个对象,对象数组中的其他对象的析构函数就不会被调用,结果造成了内存泄露。

如果在方括号中间放了一个比对象数组大小还大的数字,那么编译器就会调用无效对象(内存溢出)的析构函数,会造成堆的奔溃。如果方括号中间的数字值比对象数组的大小小的话,编译器就不能调用足够多个析构函数,结果会造成内存泄露。

释放单个对象、单个基本数据类型的变量或者是基本数据类型的数组不需要大小参数,释放定义了析构函数的对象数组才需要大小参数。

 

 

4). 指向对象的指针数组不等同于对象数组

 

对象数组是指:数组中存放的是对象,只需要delete []p,即可调用对象数组中的每个对象的析构函数释放空间;

指向对象的指针数组是指:数组中存放的是指向对象的指针,不仅要释放每个对象的空间,还要释放每个指针的空间,delete []p只是释放了每个指针,但是并没有释放对象的空间,正确的做法,是通过一个循环,将每个对象释放了,然后再把指针释放了;

 

 

5). 缺少拷贝构造函数

 

两次释放相同的内存是一种错误的做法,同时可能会造成堆的崩溃

按值传递会调用(拷贝)构造函数,引用传递不会调用。

C++中,如果没有定义拷贝构造函数,那么编译器就会调用默认的拷贝构造函数,会逐个成员拷贝的方式来复制数据成员,如果是以逐个成员拷贝的方式来复制指针被定义为将一个变量的地址赋给另一个变量。

这种隐式的指针复制结果就是两个对象拥有指向同一个动态分配的内存空间的指针:

当释放第一个对象的时候,它的析构函数就会释放与该对象有关的动态分配的内存空间。

而释放第二个对象的时候,它的析构函数会释放相同的内存,这样是错误的。

所以,如果一个类里面有指针成员变量,要么必须显示的写拷贝构造函数和重载赋值运算符,要么禁用拷贝构造函数和重载赋值运算符

 

 

 

6). 缺少重载赋值运算符

 

这种问题跟上述问题类似,也是逐个成员拷贝的方式复制对象,如果这个类的大小是可变的,那么结果就是造成内存泄露;

 

 

7. 关于nonmodifying运算符重载的常见迷思

a. 返回栈上对象的引用或者指针(也即返回局部对象的引用或者指针)。导致最后返回的是一个空引用或者空指针,因此变成野指针;

b. 返回内部静态对象的引用;

c. 返回一个泄露内存的动态分配的对象。导致内存泄露,并且无法回收;

解决这一类问题的办法是重载运算符函数的返回值不是类型的引用,二应该是类型的返回值,即不是 int&而是int;

 

 

8. 没有将基类的析构函数定义为虚函数

当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源没有正确是释放,因此造成内存泄露;

 

 

附注:

 

C++资源管理机制:RAII

 

野指针指向被释放的或者访问受限内存的指针。

造成野指针的原因:

1. 指针变量没有被初始化(如果值不定,可以初始化为NULL);

2. 指针被free或者delete后,没有置为NULL, freedelete只是把指针所指向的内存给释放掉,并没有把指针本身干掉,此时指针指向的是“垃圾”内存。释放后的指针应该被置为NULL;

3. 指针操作超越了变量的作用范围,比如返回指向栈内存的指针就是野指针;

 

 

其实内存泄漏的原因可以概括为:调用了malloc/new等内存申请的操作,但缺少了对应的free/delete释放操作,总之就是,malloc/new比free/delete的数量多。

内存用完,不再使用要及时释放。

 

相关文章:

  • 张星宇:技术人如何打造影响力
  • post方式请求数据
  • 机器学习入门之认知
  • webpack项目中使用grunt监听文件变动自动打包编译
  • jmeter tcp取样器使用方法
  • (六)软件测试分工
  • Java面试题全集
  • 后缀数组专题
  • MySQL查询相关(初级)(全文重点)
  • 堆的实现(图片演示+文字讲解)
  • Ubuntu ko模块的编译
  • 通过git安装npm私有模块
  • python 安装 setuptools Compression requires the (missing) zlib module 的解决方案
  • jquery easyui-datagrid/treegrid 清空数据参考
  • 【微信公众号发红包转账】微信公众号上手机网页接收请求,通过公众号给用户发红包 开发流程...
  • .pyc 想到的一些问题
  • CentOS 7 修改主机名
  • golang 发送GET和POST示例
  • HomeBrew常规使用教程
  • JDK9: 集成 Jshell 和 Maven 项目.
  • JS 面试题总结
  • JS专题之继承
  • MySQL的数据类型
  • PAT A1092
  • STAR法则
  • ViewService——一种保证客户端与服务端同步的方法
  • Vue UI框架库开发介绍
  • 成为一名优秀的Developer的书单
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 记录一下第一次使用npm
  • 使用 QuickBI 搭建酷炫可视化分析
  • 我感觉这是史上最牛的防sql注入方法类
  • 用mpvue开发微信小程序
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • (C语言)共用体union的用法举例
  • (二)c52学习之旅-简单了解单片机
  • (翻译)terry crowley: 写给程序员
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (强烈推荐)移动端音视频从零到上手(上)
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (转) RFS+AutoItLibrary测试web对话框
  • .“空心村”成因分析及解决对策122344
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .net 4.0发布后不能正常显示图片问题
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .net core Swagger 过滤部分Api
  • .NET MVC第三章、三种传值方式
  • .Net面试题4
  • .NET是什么
  • .NET下的多线程编程—1-线程机制概述
  • @Autowired和@Resource装配