如何有效避免内存泄露

来源:互联网 发布:php调用nodejs接口 编辑:程序博客网 时间:2024/05/16 11:46

内存泄露,是程序设计开发中需要注重的一个问题,它的出现会导致系统异常或者程序崩溃。

如果在比较成熟的代码上再去处理memory leak问题,则需要花费了很大的时间和精力去查找,无疑增加了解决的成本和难度,确切地说是补救措施。

所以平时需要养成良好的coding习惯。尽管优秀的coding实践可以确保减少泄露,但是根据经验,当使用大量的函数对相同的内存块进行处理时,还是可能出现内存泄露的,尤其是在碰到错误路径的情况下更是如此!

1. 内存泄露的定义:

指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,
由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
A memory leak is a particular type of unintentional memory consumption by a computer program where the program fails to release memory when no longer needed. This condition is normally the result of a bug in a program that prevents it from freeing up memory that it no longer needs.This term has the potential to be confusing, since memory is not physically lost from the computer. Rather, memory is allocated to a program, and that program subsequently loses the ability to access it due to program logic flaws.


2.常见内存泄露的类型。

a.heap leak,我们常说的内存泄露,一般是指heap memory,即堆内存的泄露。它就是在堆中分配的,大小任意,内存块的大小可以是在程序运行期间决定的。

我们常使用malloc,new,realloc等func从堆中来申请一块内存。但是我们必须注意的是,使用完这块内存之后,必须调用free,delete来显示地释放掉这块内存,如果不释放,这块申请的内存就不能再次使用,如果我们有多次地调用该func,则会出现内存逐渐耗尽。

b.Resource Leak,系统资源泄露主要是指程序使用系统分配的资源,如Bitmap,handle,socket等没有使用乡音的函数释放掉,导致系统支援的浪费,严重可能导致系统效能降低,系统运行不稳定。


3.防止方法。

1.Heap memory: malloc\realloc ------ free。    new \new[] ---------- delete \delete[]

    在代码量比较少的情况下,可以自行检测,确保两个函数成双使用。

2.malloc--free,new--delete,尽量不要在一个函数体中间return,否则有的分配了的内存资源就得不到释放。

3.构造函数失败?

4. c++中有智能指针的概念,sp和wp。这也是内存管理,避免内存泄露的一个方法。不过这个概念相对难度大一些。

5.代码检测工具的使用。比如valgrind,它会在跟着整个程序运行一遍后显示内存的使用和释放情况,下一篇将讲述该工具的使用。


在程序代码编写过程中,假如我们没有删除一个指针,就对其重新赋值,比如说

#include <iostream>
using namespace std;
int main( )
{
int *p = new int ;
p = new int;
return 0;
}

在这里我们使用了new运算符,给指针变量p申请了一块int类型大小的内存。在没有删除这块内存空间前,又重新对p进行了地址覆盖。这样就会造成内存泄露。这是因为:main()函数中第一行定义了一个指针p,并使其指向一块内存空间,第二行又将一块新的内存空间的地址赋给了p。这样,第一行所开辟的那块内存空间就无法再使用了。因为指向它的指针p,现在已经指向了第二块空间。指针变量p只能保存一个地址,对它重新赋值则表示以前的地址被覆盖,假如该地址的内存空间没有被释放,那么,你将无法再次通过指针p来访问先前的那块内存空间。因为此时的指针变量p记录的是第二块内存的地址。

所以说,这个程序应该这样写:
#include <iostream>
using namespace std;
int main( )
{
int *p = new int ;
delete p;
p = new int;
return 0;
}


在将第二块内存空间地址赋给指针p之前,我们要使用delete删除先前的那块内存空间,这样才不会造成内存泄露。通常new/delete、malloc/free是搭配使用的。new/delete是C++提供的运算符,而malloc/free是C/C++语言的标准库函数。
假如我们暂时不想删除第一块内存空间,那么我们也可以这么做:就是定义两个指针,

#include <iostream>
using namespace std;
int main( )
{
int *p1 = new int;
int *p2 = new int ;
return 0;
}

分别用两个指针来指向两块内存空间,这样每块空间都有一个指针来指向,也就不会造成找不到某块空间的内存泄露现象。
这里需要注意的是:你在使用new以后,假如不再使用该块内存空间,那么一定要用delete来释放它。
还有一种情况是,我们创建动态数组时,动态分配的内存最后也必须释放,否则,内存最终也会逐渐耗尽。如有以下代码:
int *p = new int[30];


我们在自由存储区创建分配了30个int型元素的数组,并返回指向该数组第一个元素的指针,此返回值初始化了指针p。如果我们不需要使用动态创建的数组时,就必须显式的将其占用的存储空间返还给程序的自由存储区。C++语言为指针提供了delete[ ]表达式释放指针所指向的数组空间:
delete [ ]p;
该语句回收了p所指向的数组,把相应的内存返还给自由存储区。

注意:在关键字delete和指针之间的方括号是必不可少的,它告诉编译器该指针指向的是自由存储区中的数组,而并非单个对象。如果遗漏了方括号,这是一个编译器无法发现的错误,将导致程序在运行时出错。

0 2
原创粉丝点击