C/C++内存管理必知必会

C/C++内存管理必知必会

1.C语言三种内存分配方式

  • 静态存储区分配
  • 栈上分配
  • 堆上分配

静态存储区也称为全局数据区,包含的数据类型比较多,有全局变量、静态变量、一般常量、字符常量等。其内存分配在程序的整个运行期间都存在,其内存在程序结束后才释放。

栈区,用于存放函数的参数值,局部变量的值等。其在函数执行时,函数内部的局部变量的存储单元会在栈上创建,等函数执行结束后,这些存储单元会自动释放。

堆区,一般由程序员分配和释放,若程序员不释放,等程序运行结束后由操作系统自动回收。malloc和free等函数操作的就是这块内存。

2. 堆与栈的区别

堆与栈主要区别有:

  1. 内存申请方式上
  • 栈:由系统自动分配。例如在声明函数的一个局部变量int b,系统自动在栈中为b开辟空间。
  • 堆:需要程序员自己申请。C语言中用malloc函数,需指明大小;C++用new运算符,不需要自己指明大小
  1. 内存申请大小的限制
  • 栈:栈空间很有限。其中栈顶的地址和栈的最大容量是系统预先规定好的,在windows下栈的大小是2M。如果申请的空间超过栈的剩余空间时将会提示overflow。
  • 堆:堆是一个很大的自由存储区,空间比栈的空间大很多,其大小受限于计算机系统中有效的虚拟内存。
  1. 内存的数据结构
  • 栈:栈是由高地址向地址拓展的数据结构,是一块连续的内存区域。
  • 堆:堆是高地址拓展的数据结构,且不连续的内存区域。这是因为系统是用链表来存储空闲的内存地址,自然是不连续的,且链表的遍历方向是由低地址向高地址的。当系统收到程序的申请时,就会遍历链表,需要一个空间大于所申请空间的堆节点,然后再将节点从内存空闲节点链表中删除,将该节点的空间分配给程序。
  1. 申请效率
  • 栈:栈是由系统自动分配的,速度较快,程序员无法控制。
  • 堆:堆是由程序员使用malloc或new来主动申请,系统收到申请后再分配空间。其速度比较慢,且容易产生内存碎片。
  1. 存储内容
  • 栈:在函数调用时,第一个进栈的是主函数中下一条指令的地址(函数调用的下一个可执行语句),然后是函数的各个参数进栈,在C语言编译器中,函数参数是由右向左进栈的;接着的是函数的局部变量。注意静态变量是不入栈的。
  • 堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员自己安排。

4. C语言参数压栈顺序

压栈顺序是自右向左的。

该入栈方式有个好处就是可以动态变化参数的个数。通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底。除非知道参数个数,否则是无法通过栈指针的相对位移求得最左边的参数。这样就变成了左边参数的个数不确定,正好和动态参数个数的方向相反。因此采用该入栈方式主要原因是为了支持可变长参数形式。

5. C语言中栈的作用

  1. C语言中用栈来存储临时变量,临时变量包括函数参数和函数内部定义的临时变量。在函数调用中,和函数调用相关的函数返回地址,函数中的临时变量、寄存器均保存在栈中。
  2. 栈是多线程编程的基础、基石。每个线程都最少有一个专属自己的栈,用来存储本线程运行时各个函数的临时变量和保护现场运行场景。操作系统最基本功能是支持多线程编程,支持中断和异常处理,中断和异常处理也具有专属的栈,因此栈也是操作系统多线程管理的基石。

6.C++内存管理

C/C++内存管理必知必会_第1张图片

  • 栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。
  • 堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。它与数据机构中的堆是两回事,分配方式类似于链表。
  • 全局区(静态区)(static):全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另外一块区域。程序结束后由系统释放。
  • 文字常量区:常量字符串就是放在这里。程序结束后由系统释放。
  • 程序代码区:存放函数体的二进制代码

而在C++中,虚拟内存可以分为代码段、数据段、BSS段、堆区、文件映射区及栈区六部分

  • 代码段:包括只读存储区和文本区,只读存储区存储有字符串常量,文本区存储程序的机器代码
  • 数据段:存储程序中已经初始化过的全局变量和静态变量
  • BBS段:存储未初始化过的全局变量和静态变量,以及所有被初始化为0的全局变量和静态变量
  • 堆区:调用new/malloc时在堆区动态分配内存,同时需要调用delete/free来手动释放申请的内存
  • 文件映射区:存储动态链接库和调用mmap函数(内存映射函数)进行的文件映射
  • 栈:使用栈空间存储函数返回地址、参数、局部变量、返回值

7.内存泄漏

7.1 什么是内存泄漏

内存泄漏简单点说,就是申请了一块内存,使用完毕后没有释放掉它。
内存泄漏现象一般表现为程序运行时间越长,占用的内存越来越多,最终将用尽内存,导致整个系统崩溃。如果程序申请了一块内存,却没有任何一个指针去指向它,管理它,那么这块内存就泄漏了。

7.2 检测和避免内存泄漏

其实内存泄漏的原因可以概括为:调用了malloc/new等内存申请的操作,但缺少了对应的free/delete。
避免内存泄漏的方法可以总结:

  1. 程序员要养成良好编程习惯,保证malloc/new和free/delete匹配
  2. 将分配的内存的指针以链表的形式自我管理,使用完毕后从链表中删除,程序结束时可检查链表中是否有内存没释放
  3. 使用一些工具插件用于检查malloc/new和free/delete是否匹配
  4. 使用Boost中的智能指针

你可能感兴趣的:(内存管理,C/C++)