【C++】拿下! C++中的内存管理

在这里插入图片描述

内存管理

  • 1 C++ 的内存分布
  • 2 C语言的内存管理
  • 3 C++的内存管理
    • 3.1 内置类型操作
    • 3.2 自定义类型操作
  • 4 operator new与operator delete函数(重点)
  • 5 new和delete的实现原理
    • 5.1 内置类型
    • 5.2 自定义类型
      • new的原理
      • delete的原理
      • new T[ N ] 的原理
      • lete[]的原理
  • 6 总结
    • malloc/free和new/delete的区别
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 C++ 的内存分布

内存管理是十分重要的内容,企业开发中多有服务器宕机的大事故,比如:

  1. B站崩了两次:
    2023年3月5日晚20:20左右,许多网友表示在使用B站时,手机和电脑端都无法访问视频详情页,且手机端无法查看收藏夹与历史记录。
    8月4日晚间,距离上次事故5个月后,又有许多网友反馈B站图片(视频封面)无法加载、视频无法打开、视频一直在缓冲。
  2. 腾讯一级事故:
    2023年3月29日凌晨,腾讯旗下的微信和QQ等业务曾出现崩溃状况,包括微信语音对话、朋友圈、微信支付,以及QQ文件传输、QQ空间和QQ邮箱在内的多个功能无法使用。

其中内存管理可能占有一定原因,只有我们打好内存管理的基础才能为大家做出贡献,那不然就只能赶快跑路了。
首先我们就要了解内存分布的情况是什么样的。
在这里插入图片描述

其中

  1. 栈又叫堆栈—非静态局部变量、函数参数、返回值等等。最重要的栈是向下增长的!空间有限但效率较高。
  2. 内存映射段是高效的 I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享内存,叫做进程间通信。
  3. 堆用于程序运行时的动态内存分配,注意堆是向上增长的。会产生内存碎片(如果不停开辟空间会导致内存浪费)且效率较慢。
  4. 数据段—储存全局数据和静态数据。
  5. 代码段—可执行的代码 / 只读常量。

堆和栈是我们常用到的区域,栈不需要我们进行管理,需要我们多加注意的就是堆区域

2 C语言的内存管理

我们回忆一下C语言的内存管理,大概是下面四个函数的使用:

  1. malloc 直接开辟空间
  2. calloc 开辟并初始化空间
  3. realloc 扩容
  4. free 释放

接下来我们来看C++ 的内存管理,来欣赏祖师爷的绝妙手笔~

3 C++的内存管理

首先C语言的内存管理可以在C++中使用,但是有些地方就显得比较复杂,因此我们需要C++的内存管理
C++的内存管理是通过new 操作符 和 delete 操作符来实现的。

3.1 内置类型操作

首先来看对于内置类型的操作:

int main(){//开辟申请一个int的空间int* p1 = new int;//开辟申请一个int的空间,并初始化为10int* p2 = new int(10);//开辟申请 3 个int的空间	int* p3 = new int[3];//开辟申请 3 个int的空间,并初始化为1,2,3int* p4 = new int[3] {1, 2, 3};//释放空间delete p1;delete p2;delete[] p3;delete[] p4;return 0;
}

在这里插入图片描述
通过一个new 就可以完成复杂的开辟空间操作。
在这里插入图片描述

注意:
每次使用完空间,一定要释放掉。申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用
new[]和delete[],注意:匹配起来使用

3.2 自定义类型操作

对于自定义类型 new/delete 和 malloc/free最大区别是 new / delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
来看使用:

#include"Date.h"int main() {Date* p1 = new Date(2024, 2, 28);p1->show();delete p1;return 0;
}

在这里插入图片描述
注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会

4 operator new与operator delete函数(重点)

new 和 delete 是用户进行动态内存申请和释放的操作符,而 operator new与operator delete 是系统提供的全局函数,new 在底层就是通过调用operator new 来申请空间,delete就是通过operator delete 来释放空间。
到这里我们大概就知道了operator new与operator delete函数应该是对 malloc 和 free的封装。
我们进入反汇编就可以验证这一点:


// new() Fallback Ordering
//
// +----------+
// |new_scalar<---------------+
// +----^-----+               |
//      |                     |
// +----+-------------+  +----+----+
// |new_scalar_nothrow|  |new_array|
// +------------------+  +----^----+
//                            |
//               +------------+----+
//               |new_array_nothrow|
//               +-----------------+_CRT_SECURITYCRITICAL_ATTRIBUTE
void* __CRTDECL operator new(size_t const size)
{
00007FF7C6A17D60  mov         qword ptr [rsp+8],rcx  
00007FF7C6A17D65  sub         rsp,38h  for (;;){if (void* const block = malloc(size))
00007FF7C6A17D69  mov         rcx,qword ptr [size]  
00007FF7C6A17D6E  call        malloc (07FF7C6A11401h)  
00007FF7C6A17D73  mov         qword ptr [rsp+20h],rax  
00007FF7C6A17D78  cmp         qword ptr [rsp+20h],0  
00007FF7C6A17D7E  je          operator new+27h (07FF7C6A17D87h)  {return block;
00007FF7C6A17D80  mov         rax,qword ptr [rsp+20h]  
00007FF7C6A17D85  jmp         operator new+4Bh (07FF7C6A17DABh)  }if (_callnewh(size) == 0)
00007FF7C6A17D87  mov         rcx,qword ptr [size]  
00007FF7C6A17D8C  call        _callnewh (07FF7C6A1150Ah)  
00007FF7C6A17D91  test        eax,eax  
00007FF7C6A17D93  jne         operator new+49h (07FF7C6A17DA9h)  {if (size == SIZE_MAX)
00007FF7C6A17D95  cmp         qword ptr [size],0FFFFFFFFFFFFFFFFh  
00007FF7C6A17D9B  jne         operator new+44h (07FF7C6A17DA4h)  {__scrt_throw_std_bad_array_new_length();
00007FF7C6A17D9D  call        __scrt_throw_std_bad_array_new_length (07FF7C6A1170Dh)  }
00007FF7C6A17DA2  jmp         operator new+49h (07FF7C6A17DA9h)  else{__scrt_throw_std_bad_alloc();
00007FF7C6A17DA4  call        __scrt_throw_std_bad_alloc (07FF7C6A111E0h)  }}// The new handler was successful; try to allocate again...}
00007FF7C6A17DA9  jmp         operator new+9h (07FF7C6A17D69h)  
}
00007FF7C6A17DAB  add         rsp,38h  
00007FF7C6A17DAF  ret  

在这里插入图片描述
显然operator new与operator delete函数应该是对 malloc 和 free的封装。

5 new和delete的实现原理

5.1 内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL,需要我们来判断异常

5.2 自定义类型

new的原理

  1. 调用 operator new 函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造。

delete的原理

  1. 在空间上执行析构函数,完成资源清理工作。
  2. 调用operator delete函数释放空间。

new T[ N ] 的原理

  1. 调用operator new [ ]函数,在operator new[ ]实际调用operator new 函数完成N个对象空间的申请。
  2. 在申请的空间执行N次构造函数。
  3. 注意 开辟空间会多开一些来储存个数N。

lete[]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

在这里插入图片描述
在这里插入图片描述

6 总结

malloc/free和new/delete的区别

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。
不同的地方是:

  1. malloc和free是函数,new和delete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/707833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

day02_前后端环境搭建(前端工程搭建,登录功能说明,后端项目搭建)

文章目录 1. 软件开发介绍1.1 软件开发流程1.2 角色分工1.3 软件环境1.4 系统的分类 2. 尚品甄选项目介绍2.1 电商基本概念2.1.1 电商简介2.1.2 电商模式B2BB2CB2B2CC2BC2CO2O 2.2 业务功能介绍2.3 系统架构介绍2.4 前后端分离开发 3. 前端工程搭建3.1 Element-Admin简介3.2 El…

idea打包报错,clean、package报错

一、idea在打包时&#xff0c;点击clean或package报错如下&#xff1a; Error running ie [clean]: No valid Maven installation found. Either set the home directory in the configuration dialog or set the M2_HOME environment variable on your system. 示例图&#xf…

深入理解分库、分表、分库分表

前言 分库分表&#xff0c;是企业里面比较常见的针对高并发、数据量大的场景下的一种技术优化方案&#xff0c;所谓"分库分表"&#xff0c;根本就不是一件事儿&#xff0c;而是三件事儿&#xff0c;他们要解决的问题也都不一样&#xff0c;这三个事儿分别是"只…

C语言:字符函数 字符串函数 内存函数

C语言&#xff1a;字符函数 & 字符串函数 & 内存函数 字符函数字符分类函数字符转换函数tolowertoupper 字符串函数strlenstrcpystrcatstrcmpstrstrstrtok 内存函数memcpymemmovememsetmemcmp 字符函数 顾名思义&#xff0c;字符函数就是作用于字符的函数&#xff0c;…

【MySQL | 第一篇】undo log、redo log、bin log三者之间的区分?

undo log、redo log、bin log三者之间的区分&#xff1f; 从 产生的时间点、日志内容、用途 三方面展开论述即可 1.undo log——撤销日志 时间点&#xff1a;事务开始之前产生&#xff0c;根据当前版本的数据生成一个undo log&#xff0c;也保存在事务开始之前 作用&#xf…

【亚马逊云新春特辑②】构生成式 AI 文生图工具之借助ControlNet进行AI绘画创作【生成艺术二维码】

文章目录 1.1 生成艺术二维码1&#xff09;制作基础二维码2&#xff09;确定艺术风格3&#xff09;生成艺术二维码4&#xff09;结果优化 AIGC 的可控性是它进入实际生产最关键的一环。在此之前&#xff0c;许多用户希望 AI 生成的结果尽可能符合要求&#xff0c;但都不尽如人意…

linux centos7.9改dns和ip

vi /etc/sysconfig/network-scripts/ifcfg-ens32 &#xff1a;wq后 重启网络服务 systemctl restart network —————————————————————————— 篇外话题 软件下载 xshell可以从腾讯软件中心下载

使用 C++23 协程实现第一个 co_yield 同步风格调用接口--Qt计算排列组合

上一篇介绍了 co_await 的例子。与 co_await 类似&#xff0c;在C23的协程特性里&#xff0c; co_yield 用于从协程执行过程中暂停&#xff0c;并返回值。这个功能乍一听起来很奇怪&#xff0c;网上的例子大多是用一个计数器来演示多次中断协程函数&#xff0c;返回顺序的计数值…

【MySQL】DCL

DCL英文全称是Data Control Language(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权限。 1. 管理用户 在MySQL数据库中&#xff0c;DCL&#xff08;数据控制语言&#xff09;是用来管理用户和权限的语句集合。通过DCL语句&#xff0c;可以创建、修改、删…

机器遗忘同等重要,AI如何忘记不良数据,保护用户隐私?

引言&#xff1a;大语言模型中的机器遗忘问题 在人工智能领域&#xff0c;大语言模型&#xff08;LLMs&#xff09;因其在文本生成、摘要、问答等任务中展现出的卓越能力而备受关注。然而&#xff0c;这些模型在训练过程中可能会记住大量数据&#xff0c;包括敏感或不当的信息…

数据分析(二):学生成绩预测分析报告

目录 摘要 一、引言 二、 数据源介绍 三、 数据清洗和预处理 3.1 缺失值处理 3.2 异常值处理 3.3 数据编码 四、 探索性数据分析 4.1 可视化相关统计量 4.2 目标数据的分布情况 4.3 Pearson 相关性分析 五、 特征工程 5.1 特征构造 5.1.1 总饮酒量 5.1.2 整体关…

使用空闲电脑免费搭建一个私人的网盘

如果你也有一台空闲电脑&#xff0c;可以使用它来搭建一个私人的网盘。 这里使用的是飞梦云网盘&#xff1b; 服务端&#xff1a;下载 服务器文件使用hash校验进行储存&#xff0c;实现重复上传的文件秒传功能。 Fuse4Ui&#xff08;虚拟分区工具&#xff09;&#xff1a;下…

GaN建模:强大但富有挑战性

来源&#xff1a;Modeling GaN: Powerful but Challenging&#xff08;10年&#xff09; 文章的研究内容 这篇文章主要研究了氮化镓&#xff08;GaN&#xff09;高电子迁移率晶体管&#xff08;HEMTs&#xff09;的建模问题。GaN HEMTs是微波频段高功率发射器设计中的关键技术…

java面试题基础篇,kafka与rabbitmq面试题

1. Java 堆空间 **发生频率&#xff1a;**5颗星 造成原因 无法在 Java 堆中分配对象 吞吐量增加 应用程序无意中保存了对象引用&#xff0c;对象无法被 GC 回收 应用程序过度使用 finalizer。finalizer 对象不能被 GC 立刻回收。finalizer 由结束队列服务的守护线程调用&a…

BOOT电路

本质&#xff1a;BOOT电路本质上是单片机的引脚 作用&#xff1a;BOOT电路的作用是用于确定单片机的启动模式 使用方法&#xff1a;在单片机上电或者复位时给BOOT管脚设置为指定电平即可将单片机设置为指定启动模式。 原理&#xff1a;单片机上电或复位后会先启动内部晶振&a…

【C++进阶】哈希 + unordered系列容器

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

华为 OD 一面算法原题

2.2 亿彩票公布调查结果 昨天&#xff0c;闹得沸沸扬扬的《10 万中 2.2 亿》的彩票事件&#xff0c;迎来了官方公告。 简单来说&#xff0c;调查结果就是&#xff1a;一切正常&#xff0c;合规合法。 关于福利彩票事件&#xff0c;之前的推文我们已经分析过。 甚至在后面出现《…

鸿运(通天星CMSV6车载)主动安全监控云平台敏感信息泄露漏洞

文章目录 前言声明一、系统简介二、漏洞描述三、影响版本四、漏洞复现五、修复建议 前言 鸿运主动安全监控云平台实现对计算资源、存储资源、网络资源、云应用服务进行7*24小时全时区、多地域、全方位、立体式、智能化的IT运维监控&#xff0c;保障IT系统安全、稳定、可靠运行…

unity初学问题:如何修改图片的坐标

如图&#xff0c;我们想要修改图片的轴心点坐标&#xff08;Pivot&#xff09; 选择图片组 打开编辑器在里面修改即可&#xff08;最下面的Custom Pivot&#xff09;

golang使用gorm操作mysql1

1.mysql连接配置 package daoimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gorm/logger" )var DB *gorm.DB// 连接数据库&#xff0c;启动服务的时候&#xff0c;init方法就会执行 func init() {username : "roo…