内存泄漏通常是指分配出去的内存未被收回,长此以往,当程序再要求分配内存时.没有足够的内存可以分配,就会报出内存泄漏(memoryleak),造成内存泄漏的原因有很多.但通常我们见到的都是编码问题导致的泄漏,比如:
1.用 malloc 分配了,但没有用 free 释放。
2.用 new 分配了,但没有用 delete 删除。
3.用 GlobalAlloc 分配,但没有用 GlobalFree 释放。
4.用 new 分配的数组,没有用 delete 删除,而是用 delete 删除。
如:
struct A {
int num;
}
struct A* pa;
pa = new A;
delete pa; //应该用delete pa删除;
分配出的内存(不论是变量还是指针),一旦释放之后就不能再进行访问或者调用等操做,重复删除也是错误的行为,因为要删除或者访问的已经不存在了,否则会产生严重错误甚至会强行关闭开发环境(所以一定要边写代码边保存哦).
new和delete是建房和拆房的关系,如果只有“建房”而没有“拆房”,那么程序就会占用内存越来越多。所以,当使用new 为某个指针分配出内存空间后,一定要记得在不需要再使用时,用delete 删除。
tips1:在使用delete时要注意的问题
比如:
int* p = new int;
*p = 1;
cout << *p << endl;
p++; //p的指向改变了,指向了下一元素
*p = 2;
cout << *p << endl;
//错误的释放:
delete p;
在 delete p 时,p指向的是第二个元素,结果该释放将产生错位:第一个元素没有被释放,而在最后多删除了一个元素。相当你盖房时盖的是前3间,可以在拆房时,漏了头一间,从第二间开始拆起,结果把不是你盖的第4房间倒给一并拆了。
如何消除这一严重错误呢?
第一种方法是把指针正确地倒回原始位置:
p--;
delete p;
但当我们的指针指向变化很多次时,在释放前要保证一步不错地一一退回,会比较困难。所以另一方法是在最初时“备份”一份。在释放时,直接释放该指针即可。
int* p = new int;
int* pbak = *p; //备份
//移动 p
……
//释放:
delete pbak;
由于pbak正是指向p最初分配后的地址,我们删除pbak,就是删除p最初的指向。此时我们不能再删除一次p。
在C语言中还有彧中方法malloc,用于分配一定大小的空间,但是malloc和new有很大区别:
1,malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
2,对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
3,因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
4,C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存
对于非内部数据类型,new/delete分配空间的同时会自动调用构造函数和析构函数,而malloc和free不会。
new/delete作为操作符可以被用户重载,而malloc和free作为标准库函数不能为用户重载。
最后,malloc/free和new/delete最好是配对使用。如果new出来的对象去free,那么对象的析构函数没有被调用,会导致程序出错
在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。
在C++中,内存泄漏的范围更大一些。有些对象被分配了内存空间,然后却不可达,由于C++中没有GC,这些内存将永远收不回来。在Java中,这些不可达的对象都由GC负责回收,因此程序员不需要考虑这部分的内存泄露。
通过分析,我们得知,对于C++,程序员需要自己管理边和顶点,而对于Java程序员只需要管理边就可以了(不需要管理顶点的释放)。通过这种方式,Java提高了编程的效率。
因此,通过以上分析,我们知道在Java中也有内存泄漏,但范围比C++要小一些。因为Java从语言上保证,任何对象都是可达的,所有的不可达对象都由GC管理。