C++基础总结系列之【内存结构】

目录

内存分区

内存图

内存四区

栈区

堆区

数据区

代码区

堆与栈的区别

动态内存管理

malloc、calloc、realloc

new/delete

new和malloc的区别

智能指针

内存对齐

what

why

没有内存对齐机制

引入内存对齐机制

how

对齐系数

有效对齐值(对齐单位)

结构体内存对齐规则

类内存对齐规则

常见的内存错误(如何避免内存泄漏)


内存分区

  • 内存图

  • 内存四区

栈区

  1. 作用:保存局部变量、函数调用参数等
  2. 生命周期:只在函数范围内存在,当函数运行结束时自动销毁

堆区

  1. 作用:保存new的对象
  2. 生命周期:遇见delete结束,如果没有主动调用delete则在程序结束后由OS自动回收

PS:

堆区与自由存储区是有区别的,二者并不等价,堆是操作系统维护的一块实际物理内存,是一个物理概念

而自由存储区是C++中通过new/delete动态分配和释放对象的存储区,是一个逻辑概念

数据区

通常又分为全局区(静态区)和 常量区

全局区(静态区)

  1. 作用:存放全局变量和static静态变量,已经初始化的在.data区域,未初始化的在.bss区域
  2. 生命周期:程序结束后由OS释放

常量区

  1. 作用:存放不可修改的常量
  2. 生命周期:程序结束后由OS释放

代码区

  1. 作用:存放程序执行代码
  • 堆与栈的区别

 
管理方式 人为管理 自动管理
分配方式 人为分配,速度慢

系统分配,速度快

空间大小 一般为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释放空间
  • 智能指针

如需进一步了解,请移步至我的另一篇文章

C++基础总结系列之【智能指针】


内存对齐

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字节为例

  1. 整个结构体根据最宽成员int的对齐系数4对齐

  2. c1对齐单位为1,按照1字节对齐,占用第0单元

  3. i相对于结构体起始地址的偏移要为4的倍数,补齐前一个成员c1,占用0-3单元,i自身占用第4-7单元

  4. c2相对于结构体起始地址的偏移要为1的倍数,占用第8单元,结构体总体大小要能够被最宽的成员的大小整除,补齐4字节

用sizeof取其大小得到12

如果添加了#pragma pack(2),则用sizeof取其大小得到8,请读者自行思考

  • 类内存对齐规则

举例,不做详细分析


常见的内存错误(如何避免内存泄漏)

RAII机制(Resource Acquisition Is Initialization,资源获取即初始化)

其本质内容是用对象代表资源,把管理资源的任务转化为管理对象的任务

将资源的获取和释放与对象的构造和析构对应起来,从而确保在对象的生存期内资源始终有效,对象销毁时资源一定会被释放

它是一种思想,并没有直接的语法说明,modern C++中的智能指针就是采用这种思想设计实现的

详细内容见:

https://blog.csdn.net/jinzhu1911/article/details/84980415

猜你喜欢

转载自blog.csdn.net/qq_37348221/article/details/115011694
今日推荐