• 常见的内存错误及其对策


    操作系统复习

    特点

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

    时隐时现,无明显症状

    分类

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

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

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

    char *p = (char *) malloc(100);  
    if (p == NULL) 
        {
            printf("No enough memory!
    ");
            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,要么是其指向合法的内存

    非法内存操作

    起因

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

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

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

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

    基本特征

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

    后果

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

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

  • 相关阅读:
    随笔35 内联函数
    随笔32 内部类,外部类,局部内部类
    随笔31 Spring的依赖注入的三种方式
    随笔30 抽象类与接口
    随笔29 Statement对象
    随笔28 Spring中的事务
    随笔27 面向对象的五大基本原则
    随笔26 java中的泛型
    html5学习笔记——HTML5 web存储
    html5学习笔记——HTML 5 视频
  • 原文地址:https://www.cnblogs.com/vincentqliu/p/6858475.html
Copyright © 2020-2023  润新知