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

内存泄露

摘自《c/c++中常见内存泄露与对策及预防措施浅析》

1 内存泄漏的发生方式
以发生的方式来分类,内存泄漏可以分为以下四类。
(1)常发性内存泄漏。

发生内存泄漏的代码会被多次执行到,每次被执行时候都会导致一块内存泄漏。
(2)偶发性内存泄漏。

发生内存泄漏的代码只有在某些特定环境或操作过程中才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
(3)一次性内存泄漏。

发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致有且仅有一块内存发生泄漏。
(4)隐式内存泄漏。

程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格地说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存,但是对于一个服务器程序,需要运行几天几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存,所以称这类内存泄漏为隐式内存泄漏。

 

2 常见内存泄露与对策

(1)在使用局部指针变量或静态指针变量中的内存泄漏。

例如:
int main()
{
int *pi;
pi=new int[100];
r e tu rn;
}
这是常见的使用局部变量时出现的内存泄漏,没有释放指针变量。再如:
int main()
{
static int *pi=0;
for(int i=0;i<10;i++)
pi=new int;
r e tu rn;
}
这是常见的使用静态指针变量时出现的内存泄漏。程序退出后,分配的10个int只有最后一个是reachable的,而前面9个int则泄漏了。
对策:释放全部指针变量。

(2)在使用动态分配内存空间中的内存泄漏。

例如:
void MyFunction(int nSize)
{
char *p= new char[nSize];
if(!GetString(p,nSize))
{
messageBox(“Error”);
return;
}
⋯ ⋯
delete p;
}
这是一个简单而又典型的内存泄漏示例,当函数GetSt ring( )调用错误时,函数MyFunction结束而指针指向的内存却没有
被释放,此时便出现了内存泄漏。在程序段入口处分配内存,在出口处释放内存,但是函数可以在任何地方退出,所以一旦有某个出口处没有释放应该释放的内存,就很容易发生内存泄漏。
对策:C/C++函数可以在任何地方退出,在每个出口处释放应该释放的内存。本例中只要在return这个出口处释放内存p即可。

(3)重复分配内存发生的内存泄漏。

例如:
void MyFunction(int nSize)
{
⋯ ⋯
char *p= new char[nSize];
char *p= new char[nSize];
⋯ ⋯
}
对策:重复分配内存,第一块内存永远无法使用。这种情况一般多发生在编码过程中使用“代码复制”时出现错误,因此复
制代码要谨慎。

(4)非空指针被重新赋值发生的内存泄漏。
给指针赋值时,没有检查指针是否为空,如果指针不空,那么指针原来指向的内存将泄漏。例如:
char *p= new char[nSize];
q = p ;
对策:当q指针不为空,对其重新赋值后,q以前指向的内存泄漏。本例中可以再动态分配一个空指针,使p指向它。

(5)缺少else处理分支导致的内存泄漏。
例如:
char *p= new char[nSize];
iCount= SortProc(p);
if(iCount<= 0)
ret= 0;
else if(iCount<= 5)
ret= DealProc(p,iCount-1);
if(ret<= 0)
delete p;
对策:当iCount>5时,ret取值不确定,当ret大于0时,没有释放p,造成内存泄漏。本例中需添加两个el se语句,用来判断
iCount >5时ret的取值,以及ret大于0时,释
放p。

(6)删除指针顺序错误导致的内存泄漏。

例如:
Test ::~ Tes t()
{
delete(p);
i f (NULL!= p && NULL!= p ->
pData)
{
f ree(p->pData) ;
}
}
对策:当p已经被删除了,那么if条件永远不成立,于是这条free语句永远不会被执行,即p->pData占用的内存没有被释放。本例中应调整删除指针顺序。

(7)析构函数忘记释放内存导致的内存泄漏。

例如:
Test ::~ Tes t()
{
}
对策:在析构函数里面对资源释放(非静态成员指针或资源)或清零(静态成员指针或资源)是一个良好的习惯,否则容易产
生内存泄漏。

(8)基类没有定义虚析构函数引起的内存泄漏。

例如:
classA
{
~A(){}//析构函数不是虚函数
}
classB:publicA// classB继承了classA
{
~B(){}
}
void main()
{
A *p = new B;
delete p;

}
对策“: delete p”调用了classA的析构函数,没有调用B的析构函数,导致classB里面申请的资源泄漏。因为在C++标准中,通过基类的指针去删除子类的对象,而基类又没有定义虚析构函数时,结果将是不确定的。

转载于:https://www.cnblogs.com/caleb/archive/2011/09/04/2166190.html

相关文章:

  • HTML5标准学习 - 编码
  • iOS内存管理规则
  • javaBean规范
  • Scala基础知识笔记0-参考链接
  • 关于Thread类中三个interrupt方法的研究与学习(转)
  • Dynamics CRM2013 Server2012R2下部署ADFS和IFD遇到的问题
  • 小气的Static,坚强的Const,疑惑的Typedef,还有居安思危的Volatile
  • hibernate中持久化对象的生命周期(三态:自由态,持久态,游离态 之间的转换)...
  • Query DSL for elasticsearch Query
  • oracle导入导出exp,imp
  • 关于Assembly.CreateInstance()与Activator.CreateInstance()方法
  • mysql 加入列,改动列,删除列。
  • 升級 Centos 6.5 的 php 版本
  • 专业(技术和流程规范)(转)
  • MVC实现RadioButtonList
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 【Leetcode】104. 二叉树的最大深度
  • Angular Elements 及其运作原理
  • ECMAScript6(0):ES6简明参考手册
  • Java IO学习笔记一
  • Java,console输出实时的转向GUI textbox
  • JS笔记四:作用域、变量(函数)提升
  • Selenium实战教程系列(二)---元素定位
  • vue.js框架原理浅析
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 今年的LC3大会没了?
  • 紧急通知:《观止-微软》请在经管柜购买!
  • MPAndroidChart 教程:Y轴 YAxis
  • 如何用纯 CSS 创作一个货车 loader
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​iOS实时查看App运行日志
  • ​Java并发新构件之Exchanger
  • !!Dom4j 学习笔记
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • $(selector).each()和$.each()的区别
  • (MATLAB)第五章-矩阵运算
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (南京观海微电子)——I3C协议介绍
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (学习日记)2024.01.09
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转)memcache、redis缓存
  • (转)甲方乙方——赵民谈找工作
  • (转)一些感悟
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .NET成年了,然后呢?