内存管理机制


内存机制

  • C中内存机制

    1) 栈:位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效;
    2) 堆:由程序员用malloc/calloc/realloc分配,free释放。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由操作系统回收;
    3) 全局区/静态区:全局变量和静态变量存放区,程序一经编译好,该区域便存在。在C语言中初始化的全局变量、静态变量和未初始化的放在相邻的两个区域。但注意:在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,故没有区分。由于全局变量一直占据内存空间且不易维护,建议少用。它们是程序结束时释放。
    4) 字符串常量存储区:专门存放字符串常量的地方,程序结束时释放
    5) 程序代码区:存放程序二进制代码的区域

  • C++中内存机制

    1) 栈:位于函数内的局部变量(包括函数实参),由编译器负责分配释放,函数结束,栈变量失效;
    2) 堆:这里与C不同的是,该堆是由new申请的内存,有delete或delete[]负责释放
    3) 自由存储区:由程序员用malloc/calloc/realloc分配,free释放。如果程序员忘记free了,则会造成内存泄露,程序结束时该片内存会由OS回收;
    4) 全局区/静态区:全局变量和静态变量存放区,程序一经编译好,该区域便存在。在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没有区分初始化变量和未初始化变量。由于全局变量一直占据内存空间且不易维护,建议少用,程序结束时释放。
    5) 常量存储区:这是一块比较特殊的存储区,专门存储不能修改的常量,注意,如果采用非正常手段更改,也可以,但不建议。

  • 内存管理注意事项

    1) 用malloc或new申请内存之后,应该立即检查指针值是否为NULL,防止使用指针值为NULL的内存,可以在函数入口处断言检测;
    2) 不要忘记为数组或动态内存赋初值(如使用calloc比malloc就要好),指针初始化为NULL,防止野指针;
    3) 避免数组或指针下标越界,特别当心发生加1或者减1的操作;
    4) 动态内存的申请和释放必须配对,防止内存泄露,具体为malloc/calloc/realloc和free配对,new和delete以及delete[]配对;
    5) 用free或者delete释放内存后,应立即将指针设置为NULL(C++中为0),防止产生“野指针”、“悬垂指针”
    6) 遇到不懂的可以尝试debug调试

堆和栈

  • 1)具体讲,现代计算机(冯诺依曼串行执行机制),都直接在代码底层支持栈的数据结构,从而体现了专门的寄存器指向栈所在的地址(SS,堆栈段寄存器,存放堆栈段地址);有专门的机器指令完成数据入栈出栈的操作(汇编中有PUSH和POP指令)。
    2)这种机制的特点是效率高,但支持数据的数据有限,一般是整数、指针、浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构(可以自定义栈结构支持多种数据类型)。栈的使用较频繁的,对子程序的调用就是直接利用栈完成的。机器的call指令里隐含了把返回地址入栈,然后跳转至子程序地址的操作,而子程序的ret指令则隐含从堆中弹出返回地址并跳转之的操作。
    3)C/C++中的函数自动变量就是直接使用栈,故当一个函数返回时,该函数的自动变量自动失效,故要避免返回栈内存和栈引用,以免内存泄露

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

  • 栈和堆的对比

    1) 栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;堆是函数库提供的功能,特点是灵活方便,数据适应面广,但效率有一定降低
    2) 栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部结构,不一定唯一,不同堆分配的内存无法互相操作;
    3) 栈空间分静态分配和动态分配,一般由编译器完成静态分配,自动释放,栈的动态分配是不被鼓励的;堆的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/释放内存匹配是良好编程的基础;
    4) 碎片问题:对堆来讲,频繁的new/delete等操作势必造成内存空间的不连续,从而造成大量的碎片,使程序的效率降低;对于栈来讲,则不会存在这个问题,因为栈是后进先出的队列;
    5) 生长方向:堆的生长方向是向上的,即内存地址增加的方向;而栈的生长方向却是向下的,是向着内存地址减少的方向增长的;
    6) 分配方式:堆都是动态分配的,没有静态分配的堆;栈有两种分配方式,但是栈的动态分配和堆不同,它的动态分配是由编译器进行释放,无需手工实现;
    7) 分配效率:栈是机器系统提供的数据结构,计算机在底层提供支持,分配由专门的堆栈段寄存器,入栈出栈有专门的机器指令,这些都决定了栈的高效率执行堆是由C/C++函数库提供的,机制比较复杂,有不同的分配算法,易产生内存碎片,需要对内存进行各种管理,效率比较栈低很多。

  • 参考文献
    http://www.cnblogs.com/ComputerG/archive/2012/02/01/2334898.html
    http://blog.csdn.net/hairetz/article/details/4141043
    http://www.blogjava.net/zhaojianhua/archive/2011/05/10/349900.html


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



内存管理机制 内存管理机制 Android 内存管理机制 Python的内存管理机制 android内存管理机制(一) JVM内存管理机制 Python内存管理机制 Qt 内存管理机制 Spark内存管理机制 Java的内存管理机制
 
粤ICP备14056181号  © 2014-2020 ITdaan.com