内存管理

来源:互联网 发布:java socket拒绝ip连接 编辑:程序博客网 时间:2024/06/10 14:06

内存分配方式有三种:
(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配,亦称动态内存分配,程序在运行的时候用malloc或new申请任意多少内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

常见的内存错误及其对策

发生内存错误是件非常麻烦的事情,编译器是无法自动发现这些错误的,通常是在程序运行时才能捕捉到,而这些错误大多没有明显的症状,时隐时现,是一件非常棘手的事情!常见的内存错误及其对策如下:
(1)内存分配未成功,却使用了它。
编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。解决方法:在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL)或if(p!=NULL)进行防错处理。
(2)内存分配虽然成功,但是尚未初始化就引用它。两个原因,一个是没有初始化,二是误以为内存的缺省初始全为0,导致引用初值错误!
内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有,不要嫌其烦的赋零值。
(3)内存分配成功并且已经初始化,但操作越过了内存的边界。
(4)忘记了释放内存,造成内存泄漏。
(5)释放了内存却继续使用它。一个可能是return了指向栈内存的指针或者引用。另外就是使用了free或delete释放了内存后,没有将指针设置为NULL,导致产生野指针。
下面有几点可以防内存出错:
(1)malloc或new申请内存之后,应该立即检查指针值是否为NULL,防止使用指针值为NULL的内存。
(2)不要忘记为数组和动态内存赋初值。防止将未初始化的内存作为右值使用。
(3)避免数组或指针的下边越界,特别要当心发生多1或者少1操作。
(4)动态内存的申请与释放必须配对,防止内存泄漏。
(5)用free或delete释放了内存之后,立即将指针设置为NULL,防止产生野指针。

指针与数组对比

数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。其地址和容量在生命期内保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,它的特征是可变,所以我们常用指针来操作动态内存,指针远比数组灵活,但也更危险。以字符串为例比较指针与数组的特性:
(1)修改内容:
这里写图片描述
用数组装的字符串是存放在全局存储或栈上的,而指针指向的字符串是存放在静态存储区。只读不写!
(2)内容复制与比较
这里写图片描述
(3)计算内存容量
这里写图片描述

到底free和delete把指针怎么啦!

别看free和delete的名字恶狠狠的,它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。
释放掉地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了野指针。如果此时不把p设置为NULL,会让人误以为p是个合法的指针。
这里写图片描述

对于指针注意两点:
(1)指针消亡了,并不表示它所指的内存会被自动释放。
(2)内存被释放了,表不表示指针会消亡或者成了NULL指针。

杜绝“野指针”

野指针不是NULL指针,是指向垃圾内存的指针,人们一般不会错用NULL指针,因为用if语句很容易判断,但是野指针也很危险的,if语句对它不起作用。野指针的成因主要有两种:
(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指,所以指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
(2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
(3)指针操作超越了变量的作用范围。这种情况让人防不胜防,主要是一对大括号就是一个生命周期。
这里写图片描述

malloc/free为什么还要new/delete

malloc与free是C++、C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
对于非内部数据类型的对象数据,必须得用new和delete,因为对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc。但也可以使用malloc只是需要做一些额外工作。
这里写图片描述
malloc的话就需要手动的执行构造和析构函数。

malloc/free使用要点
(1)函数malloc的原型如下:
void* malloc(size_t size);
示例:int * p=(int *)malloc(sizeof(int)*length)。注意需要两个要素,一个是类型转换和sizeof。
malloc返回值的类型是void* ,所以在调用malloc时要显式地进行类型转换,将void*转换成所需要的指针类型。
malloc函数本身并不识别要申请内存是什么类型,只关心内存的总字节数。我们通常记不住int,float等数据类型的变量的确切字节数。例如int变量在16位系统下是2个字节,在32位下是4字节,而float变量在16位系统下是4个字节,在32位下也是4个字节,最好使用sizeof来测试。
(2)free释放,如果对一个内存块用free释放两次,那么程序运行错误。

new/delete使用要点
(1)new比malloc要简单,其内置了类型转换和类型安全检查功能。
如int *p=new int[length];
(2)对于delete的话,释放数组的话注意使用[]。