C++基础--内存管理

  |   0 评论   |   384 浏览

    一、内存分配方式

    • 在C++中,内存分成5个区:堆、栈、自由存储区、全局/静态存储区和常量存储区

    • 1、栈
      执行函数时,局部变量的存储单元都可以在上创建,函数执行结束时这些存储单元被自动释放。
      栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

    • 2、堆
      new分配的内存块,编译器不去管它们的释放,由应用程序去控制;
      一般一个new就要对应一个delete。
      如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

    • 3、自由存储区
      由malloc(全称memory allocation)等分配的内存块,它和堆是十分相似的,不过它是用free来结束自己的生命的。

    • 4、全局/静态存储区
      全局变量和静态变量被分配到同一块内存中

    • 5、常量存储区
      这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

    二、区分堆、栈

    void f() {int* p = new int[8];}

    如上代码就包含了堆与栈,先new出来一块堆内存,指针p指向一块栈内存。
    表示:在栈内存中存放了一个指向一块堆内存的指针p。

    b012f00ebeb94b318fb12530a778a096.png

    程序经过编译、链接、生成执行程序后,堆和栈的起始地址就已经确定了(具体说,是通过“连接程序”),在一个具有反向增长的栈的CPU上,数据空间可表示如下:
    99b2665e2c384a6c8378ee94e97eb69e.png
    在内存中,“堆”和“栈”共用全部的自由空间,只不过各自的起始地址和增长方向不同,它们之间并没有一个固定的界限,如果在运行时,“堆”和 “栈”增长到发生了相互覆盖时,称为“栈堆冲突”,系统肯定垮台。由于开销方面的原因,各种编译在实现中都没有考虑解决这个问题,只有靠设计者自己解决,比如增加内存等。

    三、控制内存分配

    • C++的一个常见问题是内存分配,即对new 和 delete 操作符的失控。

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

    新手没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。
    如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。
    如果是用malloc来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
    

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

    犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。
    内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。
    所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。
    

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

    例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。
    

     4、忘记了释放内存,造成内存泄露。

    含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。
    终有一次程序突然死掉,系统出现提示:内存耗尽。
    动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。
    

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

    评论

    发表评论

    validate