目录

内存分区
-
内存图
-
内存四区
栈区
- 作用:保存局部变量、函数调用参数等
- 生命周期:只在函数范围内存在,当函数运行结束时自动销毁
堆区
- 作用:保存new的对象
- 生命周期:遇见delete结束,如果没有主动调用delete则在程序结束后由OS自动回收
PS:
堆区与自由存储区是有区别的,二者并不等价,堆是操作系统维护的一块实际物理内存,是一个物理概念
而自由存储区是C++中通过new/delete动态分配和释放对象的存储区,是一个逻辑概念
数据区
通常又分为全局区(静态区)和 常量区
全局区(静态区)
- 作用:存放全局变量和static静态变量,已经初始化的在.data区域,未初始化的在.bss区域
- 生命周期:程序结束后由OS释放
常量区
- 作用:存放不可修改的常量
- 生命周期:程序结束后由OS释放
代码区
- 作用:存放程序执行代码
-
堆与栈的区别
堆 | 栈 | |
管理方式 | 人为管理 | 自动管理 |
分配方式 | 人为分配,速度慢 | 系统分配,速度快 |
空间大小 | 一般为4GB | 一般为1MB |
内存碎片 | 堆由于new/delete分配空间不连续,会产生碎片 |
栈的地址空间是连续的,不会产生碎片 |
生长方向 | 堆向高地址扩展 | 栈向低地址扩展 |
分配效率 | 堆由函数库提供,按照一定算法在堆内存中搜索足够大小的空间,如果没有足够大小的空间,可能调用系统功能增加程序数据段的内存空间,效率较低 |
栈有专门的寄存器和指令存放栈地址以及操作栈区,效率高 |
适用情况 | 堆需要自己管理,易出错,效率低,但灵活,空间大 |
栈方便管理,效率很高,但不灵活,空间小 |
动态内存管理
-
malloc、calloc、realloc
-
new/delete
new/delete本质上其实就是对malloc/free进行的封装
new:先调用operator new分配空间,再调用构造函数初始化
delete:先调用析构函数清理对象,再调用operator delete释放空间
new[]:先调用operator new分配空间,再调用n次构造函数初始化对象
delete[]:先调用n次析构函数清理对象,再调用operator delete释放空间
-
new和malloc的区别
C | C++ |
|
性质 | malloc/free是函数 | new/delete是操作符 |
初始化 | malloc不可以初始化 | new可以初始化 |
开辟空间的位置 |
malloc开辟的空间在堆区 | new开辟的空间在自由存储区 |
开辟空间的大小 | malloc开辟空间时需要指定空间大小 | new开辟空间时只需要类型名,由编译器自己计算大小 |
成功返回值 | malloc申请成功返回void*型空间,需要使用时强转成其他类型,失败返回NULL | new申请成功返回对象指针,失败则抛出异常 |
扩容 | malloc开辟的空间如果不够用,可以使用realloc扩容 | new没有直接的扩容方式 |
是否调用构造/析构 | new在申请空间时,先调用malloc开辟空间,再调用构造函数进行初始化,在delete时会先调用析构函数清理对象,然后调用free释放空间 |
-
智能指针
如需进一步了解,请移步至我的另一篇文章
内存对齐
what
在32位系统中,int占4字节,char占1字节,将它们储存在一个结构体中,应该占用5个字节,但实际上占用了8个字节
why
上述情况出现是因为处理器存在内存存取粒度的说法——处理器处理字节的单位,通常为双字节、四字节或八字节等等
以32位系统,存取粒度为4字节为例
-
没有内存对齐机制
一个int型变量存放在地址为1开始的4个字节的地址中
处理去取int型数据时,先从0地址开始读取第一个4字节块,剔除第一个字节存放的是char
再读取下一个4字节块,剔除不想要的字节(5,6,7),最后剩下的内存合并放入寄存器,需要很多步骤
-
引入内存对齐机制
int变量只能存放在4字节的整数倍开始的地址大小内,则一次就能读取到想要的数据
how
-
对齐系数
-
有效对齐值(对齐单位)
对齐系数和结构体中最长数据类型长度相比,较小的一个
如:对齐系数为4,最长数据类型为short——2字节,则有效对齐值为2
对齐系数为4,最长数据类型为double——8字节,则有效对齐值为4
-
结构体内存对齐规则
举例:以32位系统,默认对齐系数4字节为例
-
整个结构体根据最宽成员int的对齐系数4对齐
-
c1对齐单位为1,按照1字节对齐,占用第0单元
-
i相对于结构体起始地址的偏移要为4的倍数,补齐前一个成员c1,占用0-3单元,i自身占用第4-7单元
-
c2相对于结构体起始地址的偏移要为1的倍数,占用第8单元,结构体总体大小要能够被最宽的成员的大小整除,补齐4字节
用sizeof取其大小得到12
如果添加了#pragma pack(2),则用sizeof取其大小得到8,请读者自行思考
-
类内存对齐规则
举例,不做详细分析
常见的内存错误(如何避免内存泄漏)
RAII机制(Resource Acquisition Is Initialization,资源获取即初始化)
其本质内容是用对象代表资源,把管理资源的任务转化为管理对象的任务
将资源的获取和释放与对象的构造和析构对应起来,从而确保在对象的生存期内资源始终有效,对象销毁时资源一定会被释放
它是一种思想,并没有直接的语法说明,modern C++中的智能指针就是采用这种思想设计实现的
详细内容见: