zoukankan      html  css  js  c++  java
  • C++ 内存管理

    一 C++内存区域

    1 栈: 

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

    2 堆: 

    由new分配的内存块,手动动态分配,一般一个new就要对应一个delete。[如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收]。可以使用虚拟内存,调用硬盘存储
     

    3 自由存储区:

     由malloc等分配的内存块,用free来结束自己的生命周期。姑且认为自有存储区就是堆,malloc/free与new/delete的区别,前者是c的,后者是c++的,后者会调用对象的构造/析构函数
     

    4 全局/静态存储区(数据区): 

    全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在
     

    5 常量存储区: 

    用于存放的是常量,不允许修改。
     

    6 代码区:

    存代码

    二 堆与栈

    1 栈


    具体地说,现代计算机(串行执行机制),都直接在代码底层支持栈的数据结构。这体现在,有专门的寄存器指向栈所在的地址,有专门的机器指令完成数据入栈出栈的操作。这种机制的特点是效率高,支持的数据有限,一般是整数,指针,浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构。因为栈的这种特点,对栈的使用在程序中是非常频繁的。对子程序的调用就是直接利用栈完成的。机器的call指令里隐含了把返回地址推入栈,然后跳转至子程序地址的操作,而子程序中的ret指令则隐含从堆栈中弹出返回地址并跳转之的操作。C/C++中的自动变量是直接利用栈的例子,这也就是为什么当函数返回时,该函数的自动变量自动失效的原因。

    2 堆

    和栈不同,堆的数据结构并不是由系统(无论是机器系统还是操作系统)支持的,而是由函数库提供的。基本的malloc/realloc/free 函数维护了一套内部的堆数据结构。当程序使用这些函数去获得新的内存空间时,这套函数首先试图从内部堆中寻找可用的内存空间,如果没有可以使用的内存空间,则试图利用系统调用来动态增加程序数据段的内存大小,新分配得到的空间首先被组织进内部堆中去,然后再以适当的形式返回给调用者。当程序释放分配的内存空间时,这片内存空间被返回内部堆结构中,可能会被适当的处理(比如和其他空闲空间合并成更大的空闲空间),以更适合下一次内存分配申请。这套复杂的分配机制实际上相当于一个内存分配的缓冲池(Cache),使用这套机制有如下若干原因:
    1. 系统调用可能不支持任意大小的内存分配。有些系统的系统调用只支持固定大小及其倍数的内存请求(按页分配);这样的话对于大量的小内存分类来说会造成浪费。
    2. 系统调用申请内存可能是代价昂贵的。系统调用可能涉及用户态和核心态的转换。
    3. 没有管理的内存分配在大量复杂内存的分配释放操作下很容易造成内存碎片。

    3 堆与栈区别

    栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/ 释放内存匹配是良好程序的基本要素。


        1.碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以>参考数据结构,这里我们就不再一一讨论了。
        2.生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
        3.分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
        4.分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

    三 C++ new/delete与malloc/free

    1 new/delete使用

    new:返回指向新创建对象的指针
    delete:用来释放指向动态(new)申请的内存地址的指针,delete一个指针后,要立刻把指针置0,防止野指针

    定义变量需要指定变量名,但动态分配内存c不需要制定名字,只需要指定类型
    1 int *p = new int; //p指向一个没名字,没初始化的动态分配堆地址,地址里存的值未知
    2 int *p = new int(1024); //p指向一个没名字,没初始化的动态分配堆地址,地址里存的值是int类型的1024
    3 int *p = new int(); //p指向一个没名字,没初始化的动态分配堆地址,地址里存的值是int类型的0

    delete只用来释放指向动态(new)申请的内存地址的指针,如果释放其他指针非法(指针为0除外)
    int *pi = &i;
    string str = "dwarves";
    double *pd = new double(33);
    delete str; // error: str is not a dynamic object
    delete pi; // error: pi refers to a local
    delete pd; // ok

    2 malloc/free

    c中用来开辟内存,与new/delete区别在于后者会调用对象构造/析构函数


  • 相关阅读:
    vmareworkstation 15 安装密钥
    Linux进入ftp界面退出方法
    linux安装mysql(5.1.73)
    安装http服务,用http搭建web网
    telnet远程连接
    yum出现问题解决方法
    samba
    nfs搭建
    解决VMwareworkstation无法在windows上运行
    2 shell编程
  • 原文地址:https://www.cnblogs.com/nafio/p/9137686.html
Copyright © 2011-2022 走看看