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

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

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

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

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

<>2. 堆与栈的区别

堆与栈主要区别有:

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

压栈顺序是自右向左的。

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

<>5. C语言中栈的作用

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

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

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

<>7.1 什么是内存泄漏

内存泄漏简单点说,就是申请了一块内存,使用完毕后没有释放掉它。

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

<>7.2 检测和避免内存泄漏

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

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

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信