C++——内存管理
一,为什么要有内存管理
因为在C/C++中各个内置类型或者是自定义类型的大小都不一样,而如何让各个类型在内存中合理分布就非常有必要,由此我们就需要有内存管理。
我们来看看下面这个程序中的各个变量都是如何分布的
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{static int staticVar = 1;int localVar = 1;int num1[10] = { 1, 2, 3, 4 };char char2[] = "abcd";const char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof(int) * 4);int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr1);free(ptr3);
}

各个区域的说明:
1. 栈:又叫堆栈—非静态局部变量/函数参数/返回值等
2. 内存映射段:是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
3. 堆:用于程序运行时动态内存分配
4. 数据段:存储全局数据和静态数据
5. 代码段:存储可执行代码和只读常量
二,C语言中动态内存管理的方式
在这里提一下动态内存管理方式的原因是要和后面C++的动态内存管理方式做一个对比,两个模式是一样的,但是使用还是有点不同。
C的动态内存管理主要是malloc/calloc/realloc,使用方式如下
int main()
{//mallocint* ptr1 = (int*)malloc(sizeof(int) * 4);free(ptr1);//calloc,用malloc的用法不太一样,//但都是开辟空间,而且calloc还带有初始化的功能int* ptr2 = (int*)calloc(4, sizeof(int));//realloc是追加开辟空间,如下,在ptr2的基础上在追加开辟//此时在释放时,只释放ptr3即可,具体原因可以查看以前的C内存管理的文章int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr3);return 0;
}
三,C++内存管理方式
C语言中的内存管理方式在C++中也可以使用,但是由于C的内存管理方式用起来比较复杂,而且有的场景难以应对,所以C++也引入了自己的内存管理方式:通过new和delete关键词来进行内存管理
3.1 内置类型管理
对于内置类型的开辟,malloc/free和new/delete的作用是差不多的
void test()
{//动态申请一个int的空间int* ptr1 = new int;//释放delete ptr1;//动态申请一个int的内存空间//并且初始化为10int* ptr2 = new int(10);//释放delete ptr2;//动态申请十个int的空间int* ptr3 = new int[10];//释放delete[] ptr3;//动态申请十个int的空间//并且初始化int* ptr4 = new int[10]{ 1,2,3,4 };//释放delete[] ptr4;
}

3.2 自定义类型管理
new/delete和malloc/free最大的区别就是,new/delete对于自定义来说,不止开空间和释放,也会调用其对应的构造函数和析构函数
class fun
{
public:fun(int a=0):_a(a){cout << "fun(int a=0)" << endl;}~fun(){cout << "~fun()" << endl;}
private:int _a;
};
int main()
{//开辟单个空间。malloc/free不会调用构造和析构函数//而new/delete则会fun* ptr1 = (fun*)malloc(sizeof(fun));fun* ptr2 = new fun;free(ptr1);delete ptr2;//开辟多个空间fun* ptr3 = (fun*)malloc(sizeof(fun) * 10);fun* ptr4 = new fun[10];free(ptr3);delete[] ptr4;return 0;
}

由上我们发现malloc/free和new/delete对自定义类型的开辟是不同的,明显后者更方便
注意:目前共有三组开辟方式,malloc/free,new/delete,new []/delete[],在使用的时候由于各个性质不同,所以绝对不能混着匹配,一定要匹配正确不然可能会导致程序出现崩溃。
四,operator new与operator delete函数
new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数进行空间开辟,delete在底层通过operator delete全局函数进行空间释放。
class A
{
public:A(int a=0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
int main()
{A* a = new A;delete a;return 0;
}

如上所示我们发现在用new进行动态内存申请时,是通过调用call->operator new实现的,那么operator new和operator delete的底层又是靠什么呢?
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid* p;while ((p = malloc(size)) == 0)if (_callnewh(size) == 0){// report no memory// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void* pUserData)
{_CrtMemBlockHeader* pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK); /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg(pUserData, pHead->nBlockUse);__FINALLY_munlock(_HEAP_LOCK); /* release other threads */__END_TRY_FINALLYreturn;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
虽然两个函数的实现代码有许多我们目前还无法理解的,但是从9行我们可以看出operator new底层是由malloc实现的,成功则返回,失败就抛异常,从第34行我们可以看出operator delete最终也是由free实现的
现在我们大概了解到new和delete的底层实现,那么new和delete究竟是如何完成在创建自定义类型的同时完成初始化呢?
五,new和delete的实现原理
5.1 内置类型
对于内置类型的申请,new/delete和malloc/free类似,不同的是new/delete申请和释放的是单个空间,而new[]/delete[]申请和释放的是连续空间,以及new/delete开辟失败是抛异常,而malloc/free是返回nullptr。
5.2 自定义类型
new的原理
1. 调用operator new函数申请空间
2. 在申请的空间上调用构造函数,进行对象的构造
delete的原理
1.调用对象的析构函数,完成对象中资源的清理
2. 调用operator delete函数释放对象的空间
class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
int main()
{A* aa = new A;delete aa;return 0;
}

new []的使用原则
1. 调用operator new[]函数,在该函数中实际上是调用operator new函数完成N个空间的开辟
2. 在申请的空间上执行N次函数构造
delete[]
1.先在要释放的空间上调用N次析构函数,完成N个对象的资源清理
2.在调用operator delete[]释放空间,实际上仍是调用operator delete完成N个空间的释放
class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
int main()
{/*A* aa = new A;delete aa;*/A* aa = new A[10];delete[] aa;return 0;
}

六,定位new表达式(placement-new)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
int main()
{//现在的ptr只是指向一个空间大小为A的空间的指针//由于没有调用构造函数所以不算对象A* ptr = (A*)malloc(sizeof(A));new(ptr)A(10);ptr->~A();free(ptr);return 0;
}

七,常见问题
7.1 new/delete和malloc/free的区别
共同点:都是从堆上申请的空间,并且需要手动释放
不同点:
用法的角度:
1. malloc/free是函数,new/delete是操作符
2. malloc申请的空间没有初始化,new可以初始化
3. malloc申请空间是需要手动计算类型大小,而new后面直接跟类型就可以,多个对象的话,[]中指定对象个数即可
4. malloc的返回值为void*,接收时需要强转,而new不需要
底层的角度:
5.malloc申请空间失败,返回nullptr,因此使用时需要判空,new不需要,但是new需要捕获异常
6.申请自定义类型时,malloc/free不会调用对象构造函数和析构函数,而new/delete则会在创建或者销毁时,完成对象的构造或者资源的销毁
7.2 内存泄露
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
总结
这就是今天要讲的内容,C++的内存管理仍是以C为基础进行优化,并且添加一些使用更加方便的新特性。
相关文章:

C++——内存管理
一,为什么要有内存管理因为在C/C中各个内置类型或者是自定义类型的大小都不一样,而如何让各个类型在内存中合理分布就非常有必要,由此我们就需要有内存管理。我们来看看下面这个程序中的各个变量都是如何分布的int globalVar 1; static int …...

AOP的另类用法 (权限校验自定义注解)
👳我亲爱的各位大佬们好😘😘😘 ♨️本篇文章记录的为 AOP的另类用法 (权限校验&&自定义注解) 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉…...

[数据结构]:12-快速排序(顺序表指针实现形式)(C语言实现)
目录 前言 已完成内容 快速排序实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-PSeqListFunction.cpp 04-SortCommon.cpp 05-SortFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容,除其中使用到C引用外,全为C语言代…...

运算符——“Python”
各位CSDN的uu们你们好呀,好久没有更新Python文章了,今天,小雅兰的内容就是Python中的操作符啦,那么现在,就让我们进入Python的世界吧 注释 注释是什么 注释的语法 注释的规范 输入输出 和用户交互 通过控制台输出 通…...

2022 IoTDB Summit:华为王超《Apache IoTDB 在华为云的实践》
12 月 3 日、4日,2022 Apache IoTDB 物联网生态大会在线上圆满落幕。大会上发布 Apache IoTDB 的分布式 1.0 版本,并分享 Apache IoTDB 实现的数据管理技术与物联网场景实践案例,深入探讨了 Apache IoTDB 与物联网企业如何共建活跃生态&#…...

C 语言网络编程 — PF_NETLINK sockets
目录 文章目录目录PF_NETLINK socketsPF_NETLINK sockets Linux 提供了 4 种 User Process 和 Kernel 之间进行通信的 IPC(Inter-Process Communicate,进程间通信)方式: /procioctlsysfsPF_NETLINK sockets(Netlink …...

广州银行冲刺A股上市:不良贷款规模突破100亿元,不良率飙升
又一家城商行平移申报IPO。近日,广州银行股份有限公司(下称“广州银行”)递交招股书,准备在深圳证券交易所主板上市。本次冲刺上市,广州银行计划募资约94.79亿元,国泰君安证券为其保荐机构。 截至目前&…...

【C++】bsearch函数的使用及二分法查找介绍
写程序的时候,肯定避免不了需要从集合中找到符合条件的元素,一般情况下,最简单也最常用的就是循环遍历元素,这种方法虽然写的简单,但是小数据量还行,但是数据过大的话,这样效率就低了。循环的时…...

分布式系统中的补偿机制设计问题
我们知道,应用系统在分布式的情况下,在通信时会有着一个显著的问题,即一个业务流程往往需要组合一组服务,且单单一次通信可能会经过 DNS 服务,网卡、交换机、路由器、负载均衡等设备,而这些服务于设备都不一…...

类成员的方法
初识对象 生活中或是程序中,我们都可以使用设计表格、生产表格、填写表格的形式组织数据进行对比,在程序中: 设计表格,称之为:设计类(class) 打印表格,称之为:创建对象 …...
华为OD机试真题Python实现【端口合并】真题+解题思路+代码(20222023)
端口合并 题目 有M(1<=M<=10)个端口组, 每个端口组是长度为N(1<=N<=100)的整数数组, 如果端口组间存在 2 个及以上不同端口相同, 则认为这 2 个端口组互相关联,可以合并 第一行输入端口组个数 M,再输入 M 行,每行逗号分隔,代表端口组。 输出合并后的端口组…...

自考本科计算机网络原理(04741)历年大题真题【18年10月-22年10月】
文章目录一、简答题(历年真题)18年10月-22年10月历年简答题出题情况分析2018年10月2019年4月2019年10月2020年8月2020年10月2021年4月2021年10月2022年4月2022年10月二、综合题(历年真题)2018年10月2019年4月2019年10月2020年8月2…...

计算机SCI期刊投稿,除了投稿信,还要做什么准备? - 易智编译EaseEditing
投稿信的准备 期刊的编辑往往需要一些有关作者及其论文的信息。 而作者也希望给编辑提供一些有助于其全文送审及决策的信息。 这些信息都应该包括在投稿信中。 投稿信应包括以下几方面的内容: 文题和所有作者的姓名;稿件适宜的栏目; 为什么此论文适合于在该刊而…...

Allegro如何刷新封装和库里的封装同步操作指导
Allegro如何刷新封装和库里的封装同步操作指导 在做PCB设计的过程中,有时会因为库里的封装有更新,所以PCB上使用到了这个封装时候需要和库里的同步,如下图 如何刷新,具体操作如下 点击Place点击Update Symbols...

基于Vue3手写选课组件(含时区切换,拖拽选择)
环境说明 基于vue3vite 无关联别的ui框架,组件化 初次使用vue3,技术菜,大佬勿喷 main.ts "moment": "^2.29.4","moment-timezone": "^0.5.41",import moment from moment; import momentTz from &…...

准备好了吗?加入 GDE 成长计划,成为下一位谷歌开发者专家!
谷歌开发者专家 (Google Developer Experts,GDE),又称谷歌开发者专家项目,是由一群经验丰富的技术专家、具有社交影响力的开发者和思想领袖组成的全球性社区。通过在各项活动演讲以及各个平台上发布优质内容来积极助力开发者、企业和技术社区…...
搭建帮助中心的 8 个最佳工具
网站帮助中心的作用通过向客户表明您了解他们所面临的问题以及如何提供帮助来建立信任;通过回答常见问题来改善客户服务,增强专业的品牌形象;通过减少重复发送给支持人员的电话和电子邮件,节省时间和金钱;增强您在搜索…...

LQB小板焊接V3版本的小板原理图,PCB图,注意事项和步骤
第一部分,这个部分,可以不焊接,直接用买的下载器进行下载代码,外接一个下载器,网上大概是10元左右,以后学习stm32的芯片的时候,这个下载器就是一个串口转换器,也可以使用。。 当然也…...
华为OD机试真题Python实现【翻转单词顺序】真题+解题思路+代码(20222023)
翻转单词顺序 题目 输入一个英文文章片段 翻转指定区间的单词顺序,标点符号和普通字母一样处理 例如输入字符串 I am a developer. 区间[0,3]则输出 developer. a am I 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Python)真题目录汇总 ## 输入 使用换行隔…...

微机原理和计算机组成原理复习
1:冯诺依曼机器的主要特点? 1)计算机由运算器、存储器、控制器、输入设备和输出设备五大部分组成; 2)指令和数据存储在存储器中,并可以按地址访问; 3)指令和数据均以二进制表示&…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...

快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...