c++初阶--内存管理
目录
- c/c++ 内存分布
- c++内存管理方式
- new/delete操作内置类型
- new和delete操作自定义类型
- operator new与operator delete函数
- new和delete的实现原理
- 内置类型
- 自定义类型
- malloc/free和new/delete的区别
- 内存泄露
- 什么是内存泄漏,内存泄露的危害
- 如何避免内存泄漏
在c语言中我们在想动态申请一块内存空间时,常使用malloc,realloc这类函数向栈申请一块空间,但是我们在学习了c++后发现,像struct,class这些类类型的数据很难用c语言中的malloc函数等控制申请的大小,而且十分麻烦,还得先计算类的大小。那么为了更加方便对这些类型的数据申请空间,c++提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
c/c++ 内存分布
在学习之前,我们再来回顾一下c/c++的内存分布情况,c/c++中程序内存区域划分如图:
说明:
1. 栈又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
创建共享共享内存,做进程间通信。
3. 堆用于程序运行时动态内存分配,堆是向上增长的。
4. 数据段–存储全局数据和静态数据。
5. 代码段–可执行的代码/只读常量。
读者可以通过下面这个练习题测试一下自己对于上面这些概念的理解是否到位:
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);
}
下面是答案:
尤其要注意的是,指针,无论是什么类型的指针,大小都是4/8个字节,它是用来存放地址的,和什么类型无关!
c++内存管理方式
前面我们已经提到过,c++提供了new/delete函数来替代c语言中的malloc/free函数,下面我们来讲解具体是怎么用的。
new/delete操作内置类型
void Test()
{// 动态申请一个int类型的空间int* ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 = new int(10);// 动态申请10个int类型的空间int* ptr6 = new int[3];delete ptr4;delete ptr5;delete[] ptr6;
}
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。
以上这些功能,用c语言的maloc/free函数也能实现,但对于下面我们要讲的自定义类型,malloc/free函数就显得有些无能为力了。
new和delete操作自定义类型
class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;
}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间
还会调用构造函数和析构函数A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);free(p1);delete p2;// 内置类型是几乎是一样的int* p3 = (int*)malloc(sizeof(int)); // Cint* p4 = new int;
free(p3);
delete p4;A* p5 = (A*)malloc(sizeof(A)*10);A* p6 = new A[10];free(p5);delete[] p6;return 0;
}
注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。
我们都说,c++是在c语言的基础上建立起来的,同时还兼容c语言,那么我们可以猜一下,new/delete函数底层也是用c语言中的malloc/free函数实现的,下面我们来看一看new和delete在底层会调用的两个函数:
operator new与operator delete函数
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是
系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过
operator delete全局函数来释放空间。
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *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)
通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
下面我们来看new和delete的实现原理
new和delete的实现原理
内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
自定义类型
new的原理
- 调用operator new函数申请空间
- 在申请的空间上执行构造函数,完成对象的构造delete的原理
- 在空间上执行析构函数,完成对象中资源的清理工作
- 调用operator delete函数释放对象的空间
new T[N]的原理
6. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对
象空间的申请
7. 在申请的空间上执行N次构造函数
delete[]的原理
8. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
9. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释
放空间
malloc/free和new/delete的区别
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地
方是:
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,
如果是多个对象,[]中指定对象个数即可 - malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
- 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。
内存泄露
什么是内存泄漏,内存泄露的危害
内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
如何避免内存泄漏
- 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。
- 采用RAII思想或者智能指针来管理资源。
- 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
- 出问题了使用内存泄漏工具检测。
相关文章:

c++初阶--内存管理
目录 c/c 内存分布c内存管理方式new/delete操作内置类型new和delete操作自定义类型 operator new与operator delete函数new和delete的实现原理内置类型自定义类型 malloc/free和new/delete的区别内存泄露什么是内存泄漏,内存泄露的危害如何避免内存泄漏 在c语言中我…...

Burstormer论文阅读笔记
这是CVPR2023的一篇连拍图像修复和增强的论文,一作是阿联酋的默罕默德 本 扎耶得人工智能大学,二作是旷视科技。这些作者和CVPR2022的一篇BIPNet,同样是做连拍图像修复和增强的,是同一批。也就是说同一个方向,22年中了…...

Apifox 学习笔记 - 前置操作之:动态更新请求体中的时间戳
Apifox 学习笔记 - 前置操作之:动态更新请求体中的时间戳 1. 在前置操作中添加一个:自定义脚本或公共脚本2. 定义我们所需的环境变量。3. 在请求参数中使用【时间戳】4. 检验参考资料 1. 在前置操作中添加一个:自定义脚本或公共脚本 2. 定义我…...

2023年9月 青少年软件编程等级考试Scratch二级真题
202309 青少年软件编程等级考试Scratch二级真题(电子学会等级考试) 试卷总分数:100分 试卷及格分:60 分 考试时长:60 分钟 第 1 题 点击绿旗,运行程序后,舞台上的图形是?( ) A:画…...

12.验证码以及付费代理
文章目录 一、验证码的处理1、验证码概述1、2 什么是图片验证码?1、2 验证码的作用1、3 图片验证码使用场景1、4 图片验证码的处理方案 2、图片在网页页面中的形式2、1 如何进行图片形式的转化 3、打码平台 二、代理的使用2、1 付费代理2、1、1 找付费代理服务站点2…...

使用Plotly可视化
显示项目受欢迎程度 改进图表 设置颜色,字体...

【C语言】结构体、位段、枚举、联合(共用体)
结构体 结构:一些值的集合,这些值称为成员变量。结构体的每个成员可以是不同类型的变量; 结构体声明:struct是结构体关键字,结构体声明不能省略struct; 匿名结构体:只能在声明结构体的时候声…...

“Python+”集成技术高光谱遥感数据处理与机器学习深度应用
涵盖高光谱遥感数据处理的基础、python开发基础、机器学习和应用实践。重点解释高光谱数据处理所涉及的基本概念和理论,旨在帮助学员深入理解科学原理。结合Python编程工具,专注于解决高光谱数据读取、数据预处理、高光谱数据机器学习等技术难题…...

Excel 转为 PDF,PNG,HTML等文件
1.安装 Spire.XLS for Java,下载jar包 下载地址 2.引入方式一(我这里这种方式一直无法引入,都是失败,所以用的方式二) <repositories><repository><id>com.e-iceblue</id><name>e-iceblue</na…...

docker中使用GPU+rocksdb
配置环境 delldell-Precision-3630-Tower ~ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focaldelldell-Precision-3630-Tower ~ nvcc --version nvcc: NVIDIA (R) Cuda comp…...

好用的跨平台同步笔记工具,手机和电脑可同步的笔记工具
在这个快节奏的工作环境中,每个人都在寻找一种方便又高效的方式来记录工作笔记。记录工作笔记可以帮助大家统计工作进展,了解工作进程,而如果工作中常在一个地方办公,直接选择电脑或者手机中笔记工具来记录即可,但是对…...

【Python 千题 —— 基础篇】浮点数转换为整数
题目描述 题目描述 整数转换为浮点数。 输入描述 输入一个整数。 输出描述 程序将整数转换为浮点数并输出。 示例 示例 ① 2输出: 2.0代码讲解 下面是本题的代码: # 描述: 整数转换为浮点数。 # 输入: 输入一个整数。 # 输出: 程序将整数转换…...

金融科技论文D部分
总结 以每周为例, 动量因子定义每种货币为前一周的回报率 价值因子定义为当前市值与其区块链中过去 7 天平均链上交易价值 利差因子定义为前 7 天硬币发行总量的负数除以在7天期限开始时未偿还的硬币量。 因素定义 为了避免过拟合,我们试图定义每一…...

Apache Tomcat下载安装配置使用超详细
下载安装 tomcat官网 在此我们以Tomcat 9.0.81为例,点击下载压缩包,解压到自己的文件夹。 tar.gz是linux操作系统下的安装版本。zip是windows系统下的压缩版本。Windows Service Installer是windows操作系统下的exe安装版本。 检查是否配置JDK 1.…...

基于Seata的分布式事务方案
在Seata中,有4种分布式事务实现方案 XA、AT、TCC、Saga 其中XA利用了数据库的分布式事务特性,AT相当于框架去控制事务回滚。TCC手写三个方法,saga手写两个方法。 AT的性能和编写比较折中,是最常用的一种。TCC一些视频教程中介绍…...

指令跳转:原来if...else就是goto
目录 CPU 是如何执行指令的? 从 if…else 来看程序的执行和跳转 如何通过 if…else 和 goto 来实现循环? 小结 你平时写的程序中,肯定不只有 int a 1 这样最最简单的代码或者指令。我们总是要用到 if…else 这样的条件判断语句、while 和…...

【数据库系统概论】第四章数据库安全性
数据库的安全性:保护数据库以防止不合法使用所造成的数据泄露、更改或破坏 grant和revoke语法...

如何正确的关闭Redis服务器
Redis官方原生版本是在Linux平台上开发和测试的,但是大多数初学者都是使用Windows系统来学习如何开发的。因此,官方提供了一个叫做“Microsoft Open Tech Redis”的项目,该项目专门为Windows平台提供了一个官方支持的Redis版本,但…...

MySQL日志管理和权限管理(重点)
目录 一、日志管理1.错误日志2.二进制日志3.慢查询日志 二、权限管理(重点)1.用户登录管理2.创建用户及授权3.刷新权限4.权限简介5.查看权限7.修改密码8、删除用户9、查看密码复杂度 一、日志管理 日志类型 1、错误日志:启动,停止,关闭失败报…...

Maven 使用教程(二)
一、如何创建JAR并将其安装在本地存储库中? 制作JAR文件非常简单,可以通过执行以下命令来完成: mvn package现在可以查看${project.basedir}/target目录,您将看到生成的JAR文件。 现在,您需要将生成的工件࿰…...

[Swift]同一个工程管理多个Target
1.准备 先创建一个测试工程“ADemo”,右键其Target选择Duplicate,再复制一个Target为“ADemo2”。 再选择TARGETS下方的“”,添加一个APP到项目中,这个命名为“BDemo”。 2、管理多个Target 可以对三个target分别导入不同的框…...

DevExpress Reporting中文教程 - 如何在macOS等系统中生成导出报表文档
DevExpress Reporting是.NET Framework下功能完善的报表平台,它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集,包括数据透视表、图表,因此您可以构建无与伦比、信息清晰的报表。 在本文中,我们将讨论如何在.NET MA…...

1967作为子字符串出现在单词中的字符串数目
java解法,程度:简单 说明 给你一个字符串数组 patterns 和一个字符串 word ,统计 patterns 中有多少个字符串是 word 的子字符串。返回字符串数目。 子字符串 是字符串中的一个连续字符序列。 示例 1: 输入:patter…...

CocosCreator 面试题(二)JavaScript中的prototype的理解
1、原型(prototype)的作用 在JavaScript中,每个函数都有一个特殊的属性叫做"prototype",它是一个对象。 原型(prototype)在JavaScript中用于实现对象之间的继承和共享属性。当创建一个函数时&am…...

python:从Excel或者CSV中读取因变量与多个自变量,用于训练机器学习回归模型,并输出预测结果
作者:CSDN @ _养乐多_ 本文详细记录了从Excel读取用于训练机器学习模型的数据,包括独立变量和因变量数据,以供用于机器学习模型的训练。这些机器学习模型包括但不限于随机森林回归模型(RF)和支持向量机回归模型(SVM)。随后,我们将测试数据集应用于这些模型,进行预测和…...

pycharm连接gitlab
1、下载安装gitlab 下载地址:Git - Downloading Package 下载后傻瓜式安装,注意勾选配置环境变量 未配置自己配置,电脑-属性-高级系统配置-环境变量 系统变量path:添加git安装目录下bin目录 2、检验安装完成 桌面右键git-open…...

【C/C++数据结构 - 2】:稳定性与优化揭秘,揭开插入排序、希尔排序和快速排序的神秘面纱!
文章目录 排序的稳定性插入排序插入排序的优化 希尔排序快速排序 排序的稳定性 稳定排序:排序前2个相等的数在序列中的前后位置顺序和排序后它们2个的前后位置顺序相同。(比如:冒泡、插入、基数、归并) 非稳定排序:排…...

PCL点云处理之基于强度特征的SIFT关键点提取法 (二百一十五)
PCL点云处理之基于强度特征的SIFT关键点提取法 (二百一十五) 一、算法介绍二、具体实现1.代码2.效果一、算法介绍 继续SIFT关键点的提取介绍,之前已经基于高程和颜色分别提取了关键点,这里是基于强度信息,若遇到文件无法读取强度问题,请参考上一篇博文,下面是具体的实现…...

uniapp打包配置
安卓: 首先不管是什么打包都需要证书,安卓的证书一般都是公司提供或者自己去申请。然后把包名等下图框住的信息填上,点击打包即可。 ios:ios需要使用mac到苹果开发者平台去申请证书,流程可以参考下边的链接 参考链接…...

人大金仓分析型数据库最大量限制
数据库支持的最大量限制: 维度 限制 数据库大小 无限 表大小 无限 行大小 1.6 TB 域大小 1 GB 每个表的行数 281474976710656 (2^48) 每个表 / 视图的列数 1600 每个表的索引数 无限 每个索引的列数 32 每个表的表级约束 无限 表名长度 63 字节 列出的“无限”…...