这个话题就像古时候女人的惠脚布,又长又臭哈~·前面我们讲过,分配了一个内存块但忘记了释放它,这是一种严重的错误。这样的内存块将等到程序执行结束时才会被释放掉。
如果程序会运行很长时间(例如在服务器上,注意不是所有的操作系统都想windows一样每天都要重启哈)并且在不停地申请新内存块,忘记释放那些已经不再有用的老内存块将迟早会把内存销耗殆尽,直接导致后边的new操作无法执行甚至是崩绩!
这样的编程漏洞我们称为内存泄漏(memory leak),因为它会像水池里的漏洞那样把内存池里的可用内存慢慢地消耗殆尽。
new语句所返回的地址是访问这个内存块的唯一线索,同时也是delete语句用来把这个内存块归还给内存池的唯一线索。
int *x; x = new int[1000]; delete[] x; x = NULL;
这意味着如果这个地址值(保存在×里)丢失了就会发生内存泄漏问题。
地址值会因为很多原因而丢失哦,比如因为一个指针变量被无意中改写,例如:
int *x; x = new int[3000]; x = new int[4000];//会覆盖掉int[3000] delete[] x;//释放掉int[4000],int[3000]内存丢失 x = NULL;
大家看出来了吗?这是会导致内存泄漏的情况之—。
会导致内存泄漏的另一种情况是用来保存内存块地址的指针变量作用域问题,例如:
void foo() { MyClass *x; x = new MyClass();//new出来的是存放在堆中,是没有作用域的,只有delete可以释放new生成的,而CPU退出本函数后系统会回收栈空间, 所以造成内存泄漏 }
当foo()函数结束时,括针变量x将超出它的作用域,这意味着它将不复存在,它的值当然就会丢失。
有两种方法可以用来堵住这样的漏洞:
- 第一个方法是在return语句之前的某个地方插入一条deletex语句:
void foo() { MyClass *x; x = new MyClass(); delete x; x = NULL; return; }
-
第二个方法是让函数把内存块的地址返回给它的调用者:
MyClass *foo() { MyClass *x; x = new MyClass(); return x; }
内存作用域
变量都有一个作用域:规定了它们可以在程序的哪些部分使用。
这个作用域通常就是对它们做出声明和定义的函数的函数体,如main函数或某个子函数。如果被定义在任何一个函数的外部,变量将拥有全局作用域,这意味着它们可以在整个程序中的所有函数里使用。
不过,应该尽量辞免使用全局变量,因为它们往往会让代码变得难以调试和容易出错!
动态内存不存在作用域的问题,一旦被分配,内存块就可以在程序的任何地方使用。
因为动态内存没有作用域,所以必须由程序员来跟宗它们的使用情况,并在不再需要用到它们的时候把它们及时归还给系统。
这里需要特别注意的是,虽然动态分配的内存块没有作用域,但用来保存其地址的指针变量是受作用域影响的。