c++|内存管理

c++|内存管理

  • C/C++内存分布
    • strlen 和 sizeof的区别
  • c语言动态内存管理方式
    • malloc
    • calloc
    • realloc
    • 例题
  • c++管理方式
    • new/delete操作内置类型
    • new/delete操作自定义类型
      • 证明
  • new 和 delete 的底层原理
    • operator new与operator delete函数
    • operator new 和 operator delete的 用法
    • 构造函数里面有其他的new 会死递归吗?
    • delete的小细节
      • delete 是先析构还是先operate delete
      • 为什么要new[ ] 对应 delete 【】
  • 定位new表达式(了解)
    • 什么是内存池
    • 使用格式
  • 内存泄漏
    • 什么时内存泄漏
    • 内存泄漏的危害
  • 谢谢观看

为什么c++要专门重新弄一套内存管理,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);
}

选择题一:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?____ staticGlobalVar在哪里?____
staticVar在哪里?____ localVar在哪里?____
num1 在哪里?____

请问上面填什么?(从左到右从上到下)
CCCAA
因为全局变量和satic修饰的都在静态区里
普通的变量在栈上

选择题二:
char2在哪里?____ *char2在哪里?___
pChar3在哪里?____ *pChar3在哪里?____
ptr1在哪里?____ *ptr1在哪里?____
AAADAB

对于char2 abcd字符串确实是在常量区 但是赋值给 char2的时候又拷贝了一份 char2数组名只有两种情况表示的是整个数组1sizeof(数组名)2.&数组名 其他都表示首元素地址 这里表示首元素地址

指针没有特别修饰所以在栈上。 *char2代表a a也在栈上 pchar3是一个指针 在站上 *pchar 它指向的内容在常量区(字符串在常量区)上和char2不同的是 char2根据字符串重新拷贝了一份在栈上

在这里插入图片描述

区域名特征
动态开辟的才在堆上
一般的变量
数据段/静态区全局变量或者static修饰的变量
代码段/常量区常量、字符串

注:/表示是一个东西,前者是从操作系统的角度,后者是从语言的角度

strlen 和 sizeof的区别

strlen遇到\0就结束 sizeof则要算上\0

在这里插入图片描述

c语言动态内存管理方式

malloc

在这里插入图片描述
在这里插入图片描述
作用:分配空间但不初始化

参数:要分配空间的总大小
malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available.
返回值:开辟成功则返回一个void的指针,就是因为返回的是void的指针所以每次用的时候都要强制类型转换。如果可用的空间不足则返回NULL空指针

calloc

在这里插入图片描述
作用:分配一段空间,并且初始化为零

参数:多少个元素,每个元素的大小
返回值和malloc一样

realloc

在这里插入图片描述

作用:重新分配空间
参数:以前指向该空间的指针,和新空间的大小
返回值:分会3种情况 成功1:异地拷贝,返回指针被改变原先的空间被释放 成功2:就地扩容 原先的指针不改变 失败则返回空指针。

例题

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}

一般不需要 因为对于成功1异地拷贝这种情况原先的空间已经被free了,对于成功2就地拷贝这种情况free(p3)就是free(p2)所以也不需要 但是如果失败 不free(p2)会造成内存泄漏,这种概率非常的低

c++管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力比如自定义类型的初始化,而且使用起来比较麻烦自己还要算分配的空间大小还要强制类型转换,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

new/delete操作内置类型

c语言内存管理函数不能随意初始化而c++的new可以,好感度+1
new 和delete 不用手动检查 失败了抛异常这一点就秒杀c语言的内存管理函数了 好感度+++++

#include <iostream>
#include<string.h>
using namespace std;

int main()
{
	int* s = new int(1); // 开辟了一个空间
	int* a = new int[5];// 随机在栈开辟了五个int的空间
	int* b = new int[5] {1, 2, 3, 4,5}; // 开辟了五个空间并且赋初始值
	delete s;
	delete[]a;
	delete[]b;
	cout << " " << endl;


}

注意 new 和delete 要搭配使用 new 和 delete 一对 new [] 和 delete [ ] 一对

在这里插入图片描述

new/delete操作自定义类型

除了开空间还分别调用了构造函数和析构函数

完成了c语言的内存管理函数无法做到的一点 好感++

证明

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;
	A* p5 = (A*)malloc(sizeof(A) * 10);
	A* p6 = new A[10];
	free(p5);
	delete[] p6;
	return 0;
}

在这里插入图片描述

new 和 delete 的底层原理是什么呢?

new 和 delete 的底层原理

operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,
operator new 和operator delete是系统提供的全局函数,

operator new 和 operator delete的 用法

operator new 的用法 和malloc 一样
operator delete 的用法 和 free一样

int main()
{
	int* a = (int*)operator new (4*10);
	operator delete (a);
	return 0;
}

new在底层调用operator new全局函数来申请空间 + 构造函数初始化,delete在底层通过operator delete全局函数来释放空间+析构函数恢复初始值
证明:

在这里插入图片描述

operator new 的底层是封装malloc函数的
operator new 的用法 和 malloc函数一样

在这里插入图片描述

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对
    象空间的申请
  2. 在申请的空间上执行N次构造函数

在这里插入图片描述
delete 同理

构造函数里面有其他的new 会死递归吗?

在这里插入图片描述

不会因为 new 是一个操作符 先 operater new 开辟了stack的空间 完了才调用 a的new ,a 再去开空间 a调自己的构造函数。

delete的小细节

delete 是先析构还是先operate delete

class Stack
{
public:
	Stack()
	{
		a = new int[4];
		_top = 0;
		_capacity = 4;
	}
	~Stack()
	{
		free(a);
		_top = _capacity = 0;
	}
private:
	int _top;
	int* a;
	int _capacity;
};

int main()
{
	Stack *pa = new Stack();
	delete pa;
	return 0;
}

oprate new 开辟了_a _top _capacity的空间

在这里插入图片描述

如果先operate delete _a _top _capacity的空间不见了 则 _a开辟的内存无法释放
所以先 析构再 operate delete

在这里插入图片描述

为什么要new[ ] 对应 delete 【】

我们对于A类只有一个成员 int a 开辟10个类型的A 不是应该是 40吗16进制28 哪为什么汇编的结果是16进制 30 48呢?

在这里插入图片描述

原因在于我们delete的时候不知道空间多大 用额外的空间保存了这一信息

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

当我们把析构函数注释掉时结果又正常了 原因在于编译器生成了析构函数对于A类什么也没干 可以不用调用 也就可以不知道需要调用几次delete了所以就不需要保存额外的信息

在这里插入图片描述

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;

	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};
int main()
{
	int* a = new int[10];
	delete a;
	A* p2 = new A[10];
	delete p2;
	
	return 0;
}

delete a 会报错吗?不会 因为a是内置类型 相当于只调用了 malloc 和 free
delete p2 会报错吗?我们看一下运行结果

在这里插入图片描述

报错了 原因是什么呢?因为有构造函数 多申请了额外的空间而p2不是指向开头的 不能从中间释放

在这里插入图片描述
new [] 申请的要 delete [] 释放

定位new表达式(了解)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化

什么是内存池

我们很多程序都是直接找内存分配空间,但是我们现在专门在内存中,开辟了一块大的空间单独给某一个程序分配,这叫内存池。
好比一个山上有一个和尚,要下山打水,他觉得太麻烦了,于是每次打水时都多打点,在山上修了一个池子。

使用格式

new (place_address) type或者new (place_address) type(initializer-list)

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};

// 定位new/replacement new
int main()
{
	// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没

	A* p1 = (A*)malloc(sizeof(A));
	new(p1)A;  // 注意:如果A类的构造函数有参数时,此处需要传参
	p1->~A();
	free(p1);
	A* p2 = (A*)operator new(sizeof(A));
	new(p2)A(10);
	p2->~A();
	operator delete(p2);
	return 0;
}

内存泄漏

什么时内存泄漏

内存泄漏是已经没有用的资源忘记释放了
比如

int main()
{
	int* a = new int[100 * 1024 * 1024];
	int* b = new int[100 * 1024 * 1024];
	int* c = new int[100 * 1024 * 1024];
	return 0;
}

内存泄漏的危害

我们试着运行上面这个程序
在这里插入图片描述
但是当我们结束程序的时候内存又恢复正常了
在这里插入图片描述

这意味着我们可以不用管内存泄漏吗?不是的因为我们写的很多程序都要跑在服务器上可不敢随时停止运行,这会造成巨大的经济损失,比如去年的滴滴服务器挂了一会儿亏了好几个亿。
长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

谢谢观看

thank you

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

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

相关文章

独家揭秘:AI大模型的神秘面纱

AI大模型&#xff0c;是当下人工智能领域里备受瞩目的技术&#xff0c;在推动科技进步和社会发展方面发挥着重要作用。然而&#xff0c;AI大模型的神秘面纱始终让人们充满好奇和探究。 首先&#xff0c;让我们来揭开AI大模型的面纱。在人工智能领域中&#xff0c;大模型是指参…

Idea 开启热部署 Devtools

一、背景 当我们在 idea 中修改代码的时候&#xff0c;idea 并不会自动的重启去响应我们修改的内容&#xff0c;而是需要我们手动的重新启动项目才可以生效&#xff0c;这个是非常不方便&#xff0c;但是可以在 idea 中开启这个自动热部署的功能。 我的 idea 版本为 2022.3.3 。…

Mosquitto介绍

一、Mosquitto介绍 Eclipse Mosquitto是一个开源的MQTT消息代理&#xff08;服务器&#xff09;软件。提供轻量级的&#xff0c;支持可发布/可订阅的的消息推送模式&#xff0c;使设备对设备之间的短消息通信变得简单&#xff0c;比如现在应用广泛的低功耗传感器&#xff0c;手…

怎么将电脑excel文档内的数据转换为图片形式

你平时在办公室会遇到格式转换的问题吗&#xff1f;比如PDF转Word&#xff0c;WPS转PDF&#xff0c;PDF转TXT&#xff0c;图片转PDF等。边肖最近在工作过程中遇到了类似的问题。为了更方便的查看表格&#xff0c;需要将Excel表格转换成图片格式。遇到这样的问题&#xff0c;很多…

Excel小技巧 (2) - 如何去除和增加前导0

1. 如何去除前导0 公式&#xff1a;SUBSTITUTE(A2,0,"")&#xff0c;然后拖动十字架&#xff0c;同步所有列数据&#xff0c;轻松搞定。 2. 如何补充前导0 公式&#xff1a;TEXT(D2,"0000000") &#xff0c;0的个数是数字的完整位数。然后拖动十字架&a…

LiveNVR监控流媒体Onvif/RTSP功能-视频广场点击在线或离线时展示状态记录快速查看通道离线原因

LiveNVR视频广场点击在线或离线时展示状态记录快速查看通道离线原因 1、状态记录1.1、点击在线查看1.2、点击离线查看 2、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 1、状态记录 1.1、点击在线查看 可以点击视频广场页面中&#xff0c; 在线 两个字查看状态记录 1.2、点击离线查…

解决Windows自定义快捷键打开快捷方式慢的问题

主要是微软拼音的自学习在捣鬼。 关闭自学习即可。

免费IP地址证书

IP地址证书&#xff0c;又称为IP证书或IP地址所有权证书&#xff0c;是一种证明特定IP地址归属和合法使用的电子凭证。它通常由权威机构颁发&#xff0c;如互联网地址分配机构&#xff08;IANA&#xff09;或其下属的区域互联网注册管理机构&#xff08;RIRs&#xff09;。IP地…

MySQL 元数据锁及问题排查(Metadata Locks MDL)

"元数据"是用来描述数据对象定义的&#xff0c;而元数据锁&#xff08;Metadata Lock MDL&#xff09;即是加在这些定义上。通常我们认为非锁定一致性读&#xff08;简单select&#xff09;是不加锁的&#xff0c;这个是基于表内数据层面&#xff0c;其依然会对表的元…

第106讲:Mycat实践指南:范围分片下的水平分表详解

文章目录 1.Mycat水平拆分的分片规则2. Mycat水平拆分之范围分片2.1.使用范围分片水平分表的背景2.2.水平分表范围分片案例2.3.准备测试的表结构2.4.配置Mycat实现范围分片的水平分表2.4.1.配置Schema配置文件2.4.2.配置Rule分片规则配置文件2.4.3.配置Server配置文件2.4.4.重启…

高级语言讲义2018计专(仅高级语言部分)

1.编写完整程序解决中国古代数学家张丘健在他的《算经》中提出的”百钱百鸡问题“&#xff1a;鸡翁一&#xff0c;值钱五&#xff1b;鸡母一&#xff0c;值钱三&#xff1b;鸡雏三&#xff0c;值钱一&#xff1b;百钱买百鸡&#xff0c;翁&#xff0c;母&#xff0c;雏各几何 …

x6.js 流程图绘制笔记,常用函数

官方参考网站如下&#xff1a;https://antv-x6.gitee.io/zh/docs/tutorial/about 安装x6 输入以下命令 npm install antv/x6 --save 引用插件代码如下&#xff1a; import { Graph } from antv/x6; 创建绘制区域 this.guiX6 new Graph({container: document.querySelect…

个人社区 项目测试

目 录 一.背景及介绍二.功能详情三.手动测试1.编写测试用例2.测试 一.背景及介绍 该项目采用了前后端分离技术&#xff0c;把我们的数据保存到数据库中&#xff0c;操作对象是用户和个人文章编辑保存&#xff0c;前端的页面实现了登录&#xff0c;列表&#xff0c;编辑&#x…

基于单片机的蓝牙无线密码锁设计

目 录 摘 要 Ⅰ Abstract Ⅱ 引 言 1 1 系统总体设计 3 1.1 系统设计要求 3 1.2 系统设计思路 3 2 系统硬件设计 5 2.1 设计原理 5 2.2 主控模块 5 2.3 芯片模块 8 2.4 矩阵键盘模块 9 2.5 液晶显示模块 10 2.6 继电器驱动模块 12 2.7 蜂鸣器模块 13 2.8 蓝牙模块 14 3 系统软…

鸿蒙4.0-DevEco Studio界面工程

DevEco Studio界面工程 DevEco Studio 下载与第一个工程新建的第一个工程界面回到Project工程结构来看 DevEco Studio 下载与第一个工程 DevEco Studio 下载地址&#xff1a; https://developer.harmonyos.com/cn/develop/deveco-studio#download 学习课堂以及文档地址&#x…

Docker 快速入门实操教程(完结)

Docker 快速入门实操教程&#xff08;完结&#xff09; Docker&#xff0c;启动&#xff01; 如果安装好Docker不知道怎么使用&#xff0c;不理解各个名词的概念&#xff0c;不太了解各个功能的用途&#xff0c;这篇文章应该会对你有帮助。 前置条件&#xff1a;已经安装Doc…

Vue.js+SpringBoot开发天然气工程运维系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统角色分类2.2 核心功能2.2.1 流程 12.2.2 流程 22.3 各角色功能2.3.1 系统管理员功能2.3.2 用户服务部功能2.3.3 分公司&#xff08;施工单位&#xff09;功能2.3.3.1 技术员角色功能2.3.3.2 材料员角色功能 2.3.4 安…

nRF52832——GPIO端口的应用

nRF52832——GPIO端口的应用 nRF52832 GPIO 端口资源描述nRF52832 GPIO 寄存器介绍GPIO 端口状态的设置GPIO 输出设置 nRF52832 GPIO 输出应用点亮第一个 LED 灯硬件部分Keil 工程搭建 蜂鸣器驱动硬件设计程序编写测试验证 nRF52832 GPIO 输入应用GPIO 输入扫描流程机械按键输入…

Vue3兄弟组件传值(同级别组件传值Vue3)

简述&#xff1a; Vue3兄弟组件传值&#xff0c;我们可以使用"Mitt"插件来实现。通过使用事件总线的方式&#xff0c;我们可以将数据从一个组件传递给另一个组件&#xff0c;实现兄弟组件之间的通信。 或者利用 Vue 3 自身的provide 和 inject 响应式 API 来实现兄弟…

STM32FreeRTOS消息队列(STM32Cube高效开发)

文章目录 一、队列&#xff08;一&#xff09;简介&#xff08;二&#xff09;FreeRTOS队列特点1、入队阻塞&#xff1a;队列满了&#xff0c;此时无法继续写入数据2、出队阻塞&#xff1a;队列为空&#xff0c;此时无法读出数据3、入队阻塞解除&#xff0c;有多个任务等待时&a…
最新文章