常见的内存错误及其对策

操作系统复习

特点

编译器不能自动发现这类错误,通常是在程序运行时才能捕捉到

时隐时现,无明显症状

分类

1 内存分配未成功,却使用了它

起因 没有意识到内存分配会不成功 编程新手容易犯

解决对策 在使用内存之前,检查指针是否为空指针(NULL)

char *p = (char *) malloc(100);  
if (p == NULL) 
    {
        printf("No enough memory!\n");
        exit(0); 
    }
View Code

 

 

2 内存分配成功,但是尚未初始化就引用它

起因 没有初始化的观念 误以为内存的默认值全为0

实际情况 

内存的缺省初值究竟是什么并没有统一的标准。但是对于全局变量和静态变量如果没有手工初始化,编译器会将其初始化为零,而对栈内存和堆内存则不作任何处理。

另外,VC在Debug和Release状态下在初始化变量时所做的操作是不同的。Debug是将每个字节位都赋值成0xcc,以有利于调试。而Release的赋值是直接从内存中分配的,内容近似于随机。所以如果在没有初始化变量的情况下去使用它的值,就会导致问题发生。

解决对策 即使是赋0值也不可省略,不要嫌麻烦

 

 

3 内存分配成功,并且已经初始化,但操作越过了内存的边界

内存分配成功,并且已经初始化,但操作越过了内存的边界 例如:使用数组时经常发生下标“多1”或者“少1”的操作

解决对策: 在for语句中,注意循环次数不要搞错

访问越界会出现什么结果?

首先,它并不会造成编译错误! 就是说,C/C++的编译器并不判断和指出代码“访问越界”了。此外,数组访问越界在运行时,它的表现是不定的,有时似乎什么事也没有,程序一直运行(当然,某些错误结果已造成);有时,则是程序一下子崩溃。

 

 

4 忘记了释放内存,造成内存泄漏

忘记释放内存,造成内存泄漏(Memory Leak) “内存泄露”一词类似“原料泄露” 泄露出去的原料不能被利用,导致生产过程中原料不足。好比借东西不还 如果申请来的内存不用,别的程序也不能用,就好像这块内存泄露出去一样,造成浪费。

以下这段小程序演示了堆内存发生泄漏的情形:

void MyFunction(int nSize)
{
char* p= new char[nSize];

if( !GetStringFrom( p, nSize ) ){
MessageBox(“Error”);
return;
}
…//using the string pointed by p;
delete p;
}
View Code

当函数GetStringFrom()返回零的时候,指针p指向的内存就不会被释放。这是一种常见的发生内存泄漏的情形。程序在入口处分配内存,在出口处释放内存,但是C函数可以在任何地方退出,所以一旦对分支处理不完整或者错误处理不当的话,就会发生内存泄漏。虽然函数体内的局部变量在函数结束时自动消亡,但是局部的指针变量所指向的内存并不会被自动释放。

含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,可能看不到错误,但终有一次程序突然死掉,系统出现提示:内存耗尽。

动态内存的申请与释放必须配对,如果程序在入口处动态申请了内存,那么在程序的每个出口处都必须释放该内存空间。

解决对策

在需要的时候才malloc,并尽量减少malloc的次数 malloc的执行效率就不高,过多的malloc使程序性能下降 能用自动变量解决的问题,就不要用malloc来解决 malloc一般在大块内存分配和动态内存分配时使用

重复使用malloc申请到的内存

尽量让malloc和与之配套的free在一个函数或模块内 尽量把malloc集中在函数的入口处,free集中在函数的出口处

 

 

5 释放了内存,却继续使用它

free(ptr);        
if (ptr != NULL) //不起作用
{
    …
}
View Code

起因: 指针所指的内存被释放以后,并不表示指针会消亡 其地址仍然不变(非NULL),只是该地址对应的内存是垃圾 指向垃圾内存的指针是“野指针”

有三种情况:

(a) 程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。

(b) 函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。

(c) 使用free释放了内存后,没有将指针设置为NULL。导致产生“野指针”,即不是NULL指针,而是指向“垃圾”内存的指针。“野指针”是很危险的,因为使用if语句进行判断对它不起作用。

char *p = (char *) malloc(100);

strcpy(p, “hello”);
free(p);        // p 所指的内存被释放,但是p所指的地址仍然不变
if(p != NULL)    // 没有起到防错作用

{
    strcpy(p, “world”);    // 出错
}
View Code

解决对策

尽量把malloc集中在函数的入口处,free集中在函数的出口处

如果free不能放在函数出口处,则指针free后立即设置为NULL

不要把局部变量的地址作为返回值返回,因为该内存在函数体结束时被自动销毁

指针要么初始化为NULL,要么是其指向合法的内存

非法内存操作

起因

内存分配未成功,却使用了它

内存分配成功,但是尚未初始化就引用它

内存分配成功,并且已经初始化,但操作越过了内存的边界

释放了内存,却继续使用它

基本特征

代码访问了不该访问的内存地址

后果

几乎全是由指针混乱导致的

少数情况下,如在硬件驱动程序中的内存问题会造成操作系统的死亡

posted @ 2017-05-15 21:12  琦在江湖飘  阅读(297)  评论(0编辑  收藏  举报