【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的空间,并初始化为10
	int* p2 = new int(10);
	//开辟申请 3 个int的空间	
	int* p3 = new int[3];
	//开辟申请 3 个int的空间,并初始化为1,2,3
	int* 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♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开源现场总线协议栈(ethercat、ethernet/ip、opc ua、profinet、canopen、modbus)

ecat主站及其相关&#xff1a; 1.soem&#xff1a;GitHub - OpenEtherCATsociety/SOEM: Simple Open Source EtherCAT MasterSimple Open Source EtherCAT Master. Contribute to OpenEtherCATsociety/SOEM development by creating an account on GitHub.https://github.com/…

vue项目导出excel ,文件过大导致请求超时的处理方法

一、因为文件过大&#xff0c;请求时间较长&#xff0c;就会产生请求超时的情况&#xff0c;处理方式是可以分为三个接口&#xff0c;接口1用来获取id值&#xff0c;接口2利用id值发起请求&#xff0c;询问是否准备好下载&#xff0c;如果没准备好&#xff0c;则没隔一秒再次发…

LeetCode300.最长递增子序列

题目 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 示例 …

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

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

Linux服务器中文乱码如何解决

如果服务器上数字和英文均可正常展示&#xff0c;只有中文是奇奇怪怪的乱码&#xff0c;那么可以考虑是服务器本身字体输出有问题。 如何在服务器上安装中文宋体字体库呢&#xff0c;排查及安装字体库步骤如下&#xff1a; 使用 fc-list命令检查服务器是否安装字体库如果提示…

若依前后端分离版开源项目学习

前言&#xff1a;vscode中vue代码没有高亮显示&#xff0c;可以下载vetur插件解决&#xff0c;ctrl点击无法跳转函数定义问题&#xff0c;可以下载vue-helper插件解决&#xff1b;idea中ctrl点击函数即可跳转函数定义。 一、登录 1.生成验证码 基本思路&#xff1a; 后端生…

C#,数值计算,求解微分方程的吉尔(Gear)四阶方法与源代码

1 微分方程 微分方程&#xff0c;是指含有未知函数及其导数的关系式。解微分方程就是找出未知函数。 微分方程是伴随着微积分学一起发展起来的。微积分学的奠基人Newton和Leibniz的著作中都处理过与微分方程有关的问题。微分方程的应用十分广泛&#xff0c;可以解决许多与导数…

Ansible自动化运维(四)jinja2 模板、Roles角色详解

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

VUE3搭载到服务器

1.搭建服务器 使用 Windows 自带的 IIS 作为服务器。 步骤如下&#xff1a;https://blog.csdn.net/qq_62464995/article/details/130140673 同时&#xff0c;上面的步骤中&#xff0c;还使用了 cpolar 将 IIS 本地网址映射到公共网址。 注&#xff1a; cpolar客户端&#xf…

【React源码 - 调度任务循环EventLoop】

我们知道在React中有4个核心包、2个关键循环。而React正是在这4个核心包中运行&#xff0c;从输入到输出渲染到web端&#xff0c;主要流程可简单分为一下4步&#xff1a;如下图&#xff0c;本文主要是介绍两大循环中的任务调度循环。 4个核心包&#xff1a; react&#xff1a;…

MySQL 篇-深入了解 DML、DQL 语言(二)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 DML、DQL 语言说明 2.0 使用 DML 实现对数据管理和操作 2.1 DML - 增添数据 insert 2.2 DML - 修改数据 update 2.3 DML - 删除数据 delete 3.0 使用 DQL 实现对…

使用.NET 升级助手工具将.net framework4.8 MVC项目升级到net6

1 新建.net framework4.8 MVC项目 随便添加一个可以访问的界面用于测试 2 对当前项目进行升级 注意&#xff1a;若要进行升级&#xff0c;首先确保本地已安装相应的sdk&#xff0c;例如&#xff1a;dotnet-sdk-6.0.402-win-x64.exe1.运行cmd命令窗口&#xff0c;进入项目所在…

【蓝桥杯】快读|min和max值的设置|小明和完美序列|​顺子日期​|星期计算|山

目录 一、输入的三种方式 1.最常见的Scanner的输入方法 2.数据多的时候常用BufferedReader快读 3.较麻烦的StreamTokenizer快读&#xff08;用的不多&#xff09; StreamTokenizer常见错误&#xff1a; 二、min和max值的设置 三、妮妮的翻转游戏 四、小明和完美序列 五…

Docker之数据卷自定义镜像

目录 一、数据卷 ​二、自定义镜像 2.1自定义centos 一、数据卷 在docker中&#xff0c;数据卷是宿主机的一个可以供一个或多个容器使用的特殊目录&#xff0c;它可以在容器之间共享和重用&#xff0c;本地与容器间传递数据更高效&#xff1b;对数据卷的修改会立马有效&#…

CSS——PostCSS简介

文章目录 PostCSS是什么postCSS的优点补充&#xff1a;polyfill补充&#xff1a;Stylelint PostCSS架构概述工作流程PostCSS解析方法PostCSS解析流程 PostCSS插件插件的使用控制类插件包类插件未来的CSS语法相关插件后备措施相关插件语言扩展相关插件颜色相关组件图片和字体相关…

代码库管理工具Git介绍

阅读本文同时请参阅-----免费的Git图形界面工具sourceTree介绍 Git是一个分布式版本控制系统&#xff0c;它可以帮助开发者跟踪和管理代码历史。Git的命令行工具是使用Git的核心方式&#xff0c;虽然它可能看起来有些复杂&#xff0c;但是一旦掌握了基本命令&#xff0c;你…

基于MQTT协议实现微服务架构事件总线

一、场景描述 昨天在博客《客户端订阅服务端事件的实现方法》中提出了利用websocket、服务端EventEmitter和客户端mitt实现客户端订阅服务端事件&#xff0c;大大简化了客户端对服务端数据实时响应的逻辑。上述方案适用于单服务节点的情形。 对于由服务集群支撑的微服务架构&…

招聘系统架构的设计与实现

在当今竞争激烈的人才市场中&#xff0c;有效的招聘系统对企业吸引、筛选和管理人才至关重要。本文将探讨招聘系统的架构设计与实现&#xff0c;帮助企业构建一个高效、可靠的人才招聘平台。 ## 1. 系统架构设计 ### 1.1 微服务架构 招聘系统通常采用微服务架构&#xff0c;将…

Java JVM虚拟机面试题

Java JVM虚拟机面试题 前言1、ThreadLocal的底层原理和应用&#xff1f;2、Java中的锁池和等待池&#xff1f;3、wait()&#xff0c;yield()&#xff0c;join()&#xff0c;sleep()的区别&#xff1f;4、你们项⽬如何排查JVM问题&#xff1f;5、YGC和FGC发生时间&#xff1f;6、…

11.vue学习笔记(组件生命周期+生命周期应用+动态组件+组件保持存活)

文章目录 1.组件生命周期2.生命周期应用2.1通过ref获取元素DOM结构2.2.模拟网络请求渲染数据 3.动态组件3.1.A&#xff0c;B两个组件 4.组件保持存活&#xff08;销毁期&#xff09; 1.组件生命周期 每个Vue组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置…