C++(三)----内存管理
1.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";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. 选择题:选项: A.栈 B.堆 C.数据段 D.代码段globalVar在哪里?____ staticGlobalVar在哪里?____staticVar在哪里?____ localVar在哪里?____num1 在哪里?____char2在哪里?____ *char2在哪里?___pChar3在哪里?____ *pChar3在哪里?____ptr1在哪里?____ *ptr1在哪里?____
2. 填空题:sizeof(num1) = ____;sizeof(char2) = ____; strlen(char2) = ____;sizeof(pChar3) = ____; strlen(pChar3) = ____;sizeof(ptr1) = ____;

C\C++的内存分布如上图右边
3. 栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
4. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信
5. 堆用于程序运行时动态内存分配,堆是可以上增长的。
6. 数据段–存储全局数据和静态数据。
7. 代码段–可执行的代码/只读常量。
2.C++内存管理方式
让我们先回想一下,C语言是如何进行内存管理的?
四个函数:malloc、realloc、calloc、free。
但是它们的使用非常不方便:int* p=(int*)malloc(sizeof(int)*n);
不仅代码量大,而且当变量是自定义类型的时候,C语言的内存管理函数无法自动调用变量的构造/析构函数。所以C++有一套自己的内存管理方式:通过new和delete操作符进行动态内存管理
new
1.开辟多个空间int* p = new int[100];

2.开辟一个空间并初始化
class A
{
public:A(int a = 0): _a(a){}
private:int _a;
};A* p = new A(10);
使用小括号() 这段代码初始化了一个对象成10,并且将地址赋值给指针变量p
3.开辟多个空间并初始化
A* p = new A[5]{1,2,3};

和malloc相比,new的特点分为以下几点:
1.对于内置类型来说,new和malloc
并没有太大的区别
2.对于自定义类型来说,new会调用
自定义类型的构造函数,而malloc不会
3.new可以初始化变量的内容
delete
delete的使用方法:
1.直接使用:
int* p = new int(10);
//使用指针p
delete p;
当new堆区空间时只开辟了一份空间,释放空间时直接使用delete即可
2. 使用delete []
int* p = new int[10]{1,2,3,4};
//使用指针p
delete[] p;//这里必须使用delete [],因为是多个空间
和free相比,delete在内置类型上没什么区别,对于自定义类型则会调用其析构函数,但是有些情况需要加 [] ,而free不需要考虑这个。
3.实现原理
全局函数operator new
new 和 delete 作为两个操作符,与malloc、free函数不一样,那new是怎样开辟空间的呢?
答:new在底层调用了operator new
这个operator new是一个函数而不是运算符重载,尽管它名字中间有一个空格
库里的函数原型:
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)if (_callnewh(size) == 0){// 如果申请内存失败了,这里会抛出bad_alloc 类型异常static const std::bad_alloc nomem;_RAISE(nomem);}
return (p);
}
通过这个原型,我们发现new在底层其实还是使用了malloc来进行开辟空间。开辟空间成功,会返回指向此空间的指针;开辟空间失败,会抛异常(后面会学)
全局函数operator delete
和new类似,delete也是调用了一个函数:operator delete:
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
void operator delete(void *pUserData)
{_CrtMemBlockHeader * pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK);__TRYpHead = pHdr(pUserData);_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg( pUserData, pHead->nBlockUse );//这个是free函数的宏替换__FINALLY_munlock(_HEAP_LOCK);__END_TRY_FINALLYreturn;
}
说明delete也是用free来进行空间的释放的
总结
对于内置类型来说,new和malloc的实现是一样的,free和delete也差不多
对于自定义类型来说:
如果是new T,调用operator new函数申请空间,在申请的空间上执行构造函数,完成对象的构造。如果是new T[n],则调用operator new[]函数,完成N个对象空间的申请,在申请的空间上执行N次构造函数;
如果是delete T,在空间上执行析构函数,完成对象中资源的清理工作,调用operator delete函数释放对象的空间
如果是delete[] T,在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理,调用operator delete[]释放空间.
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在释放空间前会调用析构函数完成空间中资源的清理
拓展:内存泄露
内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不
是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死
内存泄露有两种:
1.堆内存泄露——动态分配后未进行释放
2.系统资源泄漏:指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定
如何防止内存泄露?
内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。
ps:如何一次在堆上申请4个G的内存?
// 将程序编译成x64的进程,运行下面的程序试试?
#include <iostream>
using namespace std;
int main()
{void* p = new char[0xfffffffful];//十六进制数字cout << "new:" << p << endl;return 0;
}
相关文章:
C++(三)----内存管理
1.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";char* pCh…...
使用 ShuffleNet 模型在 CIFAR-100 数据集上的图像分类
简介 在深度学习领域,图像分类任务是衡量算法性能的重要基准。本文将介绍我们如何使用一种高效的卷积神经网络架构——ShuffleNet,来处理 CIFAR-100 数据集上的图像分类问题。 CIFAR-100 数据集简介 CIFAR-100 数据集是一个广泛使用的图像分类数据集&…...
怎么利用短信接口发送文字短信
在当今这个快节奏的数字时代,即时通讯已成为人们日常生活和工作中不可或缺的一部分。而短信接口(SMS Interface),作为传统与现代通讯技术结合的典范,凭借其高效、稳定、广泛覆盖的特性,在众多领域发挥着不可…...
【C#生态园】提升C#开发效率:掌握这六款单元测试利器
从xUnit到SpecFlow:C#测试驱动开发全指南 前言 在C#开发中,单元测试和模拟框架是至关重要的工具,它们可以帮助开发人员确保代码的质量和可靠性。本文将介绍一些常用的C#单元测试框架和相关库,包括xUnit、NUnit、Moq、FluentAsse…...
【QT】自制一个简单的小闹钟,能够实现语音播报功能
做了一个自制的小闹钟,能够自己输入时间,以及对应的闹铃,时间到了自动播放设定的闹铃,可以随时取消重新设定,采用分文件编译 注意:需要在.pro文件中加入:QT core gui texttospeech 代码…...
基于深度学习的图像描述生成
基于深度学习的图像描述生成(Image Captioning)是一种将计算机视觉与自然语言处理结合的任务,其目标是通过自动生成自然语言来描述输入的图像。该技术能够理解图像中的视觉内容,并生成相应的文本描述,广泛应用于视觉问…...
Linux和C语言(Day11)
一、学习内容 讲解有参函数 形参 和 实参 形参——定义时的参数,形式上的参数,没有实际意义,语法上必须带有数据类型 void fun(int a,int b); void fun(int a[],int n); void fun(char *s); 可以是:变量、数组、指针 实参——调用…...
使用Zlib库进行多文件或者多文件夹的压缩解压缩
zlib库可在git上自己clone下来然后使用cmake工具生成解决方案,编译、生成zlib二进制文件。然后将zlib库引入项目: //zlib库支持 #include "../zlib/include/zlib.h" #ifdef _DEBUG #pragma comment(lib, "../zlib/lib/zlibd.lib") …...
CSGHub携手Nvidia NIM、阿里计算巢打造企业级私有化部署解决方案
强强联合 人工智能与大数据的迅速发展,大模型的推理应用和资产管理已成为企业数字化转型的重要组成部分,企业正寻求高效、安全的AI模型部署解决方案。为应对日益增长的计算需求和复杂的数据管理挑战,CSGHub、Nvidia和阿里云计算巢强强联手&a…...
opencv的球面投影
cv::detail::SphericalProjector 在全景图像拼接任务中,可能需要对多个图像进行球面投影以实现无缝拼接。每个cv::detail::SphericalProjector可以负责一个图像的球面投影操作。通过将多个这样的投影器存储在std::vector中,可以对一组图像依次进行投影处…...
5. 去中心化应用(dApp)
去中心化应用(dApp) 去中心化应用(dApp)是基于区块链技术构建的应用程序,其核心特性是去中心化、透明和开放。dApp与传统应用有许多显著的区别,它们在实现和功能上都带来了新的变革。以下是对dApp的详细介…...
k8s服务发布Ingress
Kubernetes暴露服务的方式目前只有三种:LoadBlancer Service、NodePort Service、Ingress,通俗来讲,ingress和之前提到的Service、Deployment,也是一个k8s的资源类型,ingress用于实现用域名的方式访问k8s内部应用。 In…...
区块链学习笔记1--比特币
区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。 从狭义上来说:区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构,并以密码学的方式保证的不可篡改和不可伪造的分布式账本。 意思就是…...
在 Vite 项目中自动为每个 Vue 文件导入 base.less
在 Vue.js 项目中,使用 Less 作为 CSS 预处理器时,我们通常会创建一个全局的样式文件(如 base.less),用于存放一些全局变量、混合、通用样式等。为了避免在每个 Vue 组件中手动导入这个文件,我们可以通过配…...
RUST 学习之全局变量
RUST 全局变量 rust 全局变量编译期初始化的全局变量静态常量静态变量原子类型的静态变量 运行期初始化的全局变量lazy_staticBox::leakOnceCell & OnceLock 参考文档 rust 全局变量 编译期初始化的全局变量 静态常量 在编译期初始化,所以其赋值只能是表达式…...
代码随想录八股训练营第三十九天| C++
前言 一、说一下 lambda函数? 1.1.Lambda 函数的一般语法如下: 1.2.捕获子句: 二、C 怎么实现一个单例模式? 2.1.懒汉式(线程不安全): 2.2.饿汉式(线程安全): 2.3.双重检查锁定ÿ…...
服务网关工作原理,如何获取用户真实IP?
文章目录 一、什么是网关二、网关工作原理 (★)三、SpringCloud Gateway3.1 Gateway 简介3.2 Gateway 环境搭建3.3 自定义路由规则 (★)3.4 局部过滤器3.5 全局过滤器(案例:获取用户真实IP地址) (★) 补充1:不同类型的客户端如何设…...
单链表的实现(C语言)
目录 1.单链表 1.1 实现单链表 1.1.1 文件创建 1.1.2 链表功能了解 1.1.3 链表的结点 1.1.4 链表的函数声明 1.1.5 链表功能的实现 链表是一种链式结构,物理结构不连续,逻辑结构是连续的,在计算机中链表的实际存储是按照一个结点内存放…...
sql语句的训练2024/9/9
1题 需要看清思路:不是将数据库中的device_id的名字改为user_infors_example,而是在查找的时候,需要将device_id看成user_infors_example来进行查找。 答案 select device_id AS user_infos_example FROM user_profile limit 2 2 当固定查找…...
【QT】常用控件-下
欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:QT 目录 👉🏻QComboBox👉🏻 QSpinBox👉🏻QDateTimeEdit👉🏻QD…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
