c++|内存管理

news2024/11/17 13:17:58

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.coloradmin.cn/o/1488728.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于 Vue3打造前台+中台通用提效解决方案(下)

47、通用组件 - 倒计时组件 特惠部分存在一个倒计时的功能,所以我们需要先处理对应的倒计时模块,并把它处理成一个通用组件。 那么对于倒计时模块我们又应该如何进行处理呢? 所谓倒计时,其实更多的是一个时间的处理,那么对于时间的处理,此时我们就需要使用到一个第三方…

Socks5代理协议:原理、应用与优势

在计算机网络中&#xff0c;代理协议是一种用于转发客户端请求的机制。Socks5是其中一种广泛使用的代理协议。它主要工作在传输层和应用层之间&#xff0c;位于OSI参考模型的第五层&#xff08;会话层&#xff09;。其设计初衷是为了帮助授权用户突破防火墙限制&#xff0c;获取…

20240304-2-计算机网络

计算机网络 知识体系 Questions 1.计算机网络分层的优点和缺点 优点 各层之间是独立的&#xff1b;灵活性好&#xff1b;结构上可分割开&#xff1b;易于实现和维护&#xff1b;能促进标准化工作。 缺点&#xff1a; 降低效率&#xff1b;有些功能会在不同的层次中重复出现&…

2000-2021年全国各省市城乡平均受教育年限数据(分城镇和农村)(含原始数据+计算过程+计算结果)

2000-2021年全国各省市城乡平均受教育年限数据&#xff08;分城镇和农村&#xff09; 1、时间&#xff1a;2000-2021年 2、范围&#xff1a;全国及31省 3、来源&#xff1a;人口与就业统计年鉴 4、指标包括&#xff1a;城乡平均受教育年限 、6岁以上总人口 未上过学、…

自动化神器 Playwright 的 Web 自动化测试解决方案!

Playwright认识 3. Playwright环境搭建 Playwright简介&#xff1a; 2020年&#xff0c;微软&#xff08;Microsoft&#xff09;开源了一个名为Playwright的工具&#xff0c;与Selenium一样入门简单&#xff0c;支持多语言&#xff08;Python、Java、Node.js、.NET&#xff0…

Java8,函数式编程应用:

持续更新中&#xff1a; 函数式(Functional)接口 什么是函数式(Functional)接口 只包含一个抽象方法的接口&#xff0c;称为函数式接口。 你可以通过 Lambda 表达式来创建该接口的对象。&#xff08;若 Lambda 表达式 抛出一个受检异常(即&#xff1a;非运行时异常)&#xff0c…

Linux学习:初识Linux

目录 1. 引子&#xff1a;1.1 简述&#xff1a;操作系统1.2 学习工具 2. Linux操作系统中的一些基础概念与指令2.1 简单指令2.2 ls指令与文件2.3 cd指令与目录2.4 文件目录的新建与删除指令2.5 补充指令1&#xff1a;2.6 文件编辑与拷贝剪切2.7 文件的查看2.8 时间相关指令2.9 …

为什么TestNg会成为Java测试框架的首选?还犹豫什么,看它!

上一篇自动化测试我们大概了解了测试的目标、测试的技术选型以及搭建平台的目标及需求&#xff0c;也确定了自动化测试方案以testNg作为整个测试流程贯穿的基础支持框架&#xff0c;那么testNg究竟有什么特点&#xff1f;本篇开始我们来详细的学习testNg这个测试框架。 为什么要…

软件设计师8--输入输出技术

软件设计师8--输入输出技术 考点1&#xff1a;输入输出技术数据传输控制方式中断处理过程例题&#xff1a; 考点1&#xff1a;输入输出技术 数据传输控制方式 √ 程序控制&#xff08;查询&#xff09;方式&#xff1a;分为无条件传送和程序查询方式两种。方法简单&#xff0…

MySQL篇—执行计划之覆盖索引Using index和条件过滤Using where介绍(第三篇,总共三篇)

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…

python实现手机号归属地查询

手机上突然收到了某银行的短信提示&#xff0c;看了一下手机的位数&#xff0c;正好是11位。我一想&#xff0c;这不就是标准的手机号码吗&#xff1f;于是一个想法涌上心头——用python的库实现查询手机号码归属地查询自由。 那实现的效果如下&#xff1a; 注&#xff1a;电…

yolov7添加spd-conv注意力机制

一、spd-conv是什么&#xff1f; SPD-Conv&#xff08;Symmetric Positive Definite Convolution&#xff09;是一种新颖的卷积操作&#xff0c;它主要应用于处理对称正定矩阵&#xff08;SPD&#xff09;数据。在传统的卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;…

【java数据结构】模拟二叉树的链式结构之孩子表示法,掌握背后的实现逻辑

&#x1f4e2;编程环境&#xff1a;idea &#x1f4e2;树结构&#xff0c;以及叶子&#xff0c;结点&#xff0c;度等一些名词是什么意思&#xff0c;本篇不再赘述。 【java数据结构】模拟二叉树的链式结构之孩子表示法&#xff0c;掌握背后的实现逻辑 1. 认识二叉树1.1 二叉树…

桂院校园导航 | 云上高校导航 云开发项目 二次开发教程 2.0

Gitee代码仓库&#xff1a;桂院校园导航小程序 GitHub代码仓库&#xff1a;GLU-Campus-Guide 演示视频 【校园导航小程序】2.0版本 静态/云开发项目 演示 云开发项目 2.0版本 升级日志 序号 板块 详情 1 首页 重做了首页&#xff0c;界面更加高效和美观 2 校园页 新增…

Python判断结构20个实例

基本理论基础 Python中的选择判断结构是一种编程中常用的控制结构&#xff0c;它用于根据条件的真假决定程序的执行路径。选择判断结构有多种类型&#xff0c;包括if语句、if-else语句、if-elif-else语句以及嵌套的选择结构。 首先&#xff0c;我们来介绍最常见的if语句。if语…

浅谈WPF之Binding数据校验和类型转换

在WPF开发中&#xff0c;Binding实现了数据在Source和Target之间的传递和流通&#xff0c;就像现实生活中的一条条道路&#xff0c;建立起了城镇与城镇之间的衔接&#xff0c;而数据校验和类型转换&#xff0c;就像高速公路之间的收费站和安检站。那在WPF开发中&#xff0c;如何…

引入本地图片报错:require is not defined

文章目录 问题分析1. 原始写法2. 最初的解决方案3. 尝试使用 require 引入4. 封装方法进行解析引入图片 问题 Vue3 Vite 使用本地图片报错&#xff1a;require is not defined 分析 1. 原始写法 刚开始我是这样写的&#xff0c;数据是这样定义的&#xff0c;但是数据没出…

Vue.js+SpringBoot开发高校实验室管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实验管理模块2.4 实验设备模块2.5 实验订单模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示五、样例代码5.1 查询实验室设备5.2 实验放号5.3 实验预定 六、免责说明 一、摘…

2024年R2移动式压力容器充装证考试题库及R2移动式压力容器充装试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年R2移动式压力容器充装证考试题库及R2移动式压力容器充装试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上…

快速幂(求解原理+例题)

目录 反复平方法&#xff08;快速幂&#xff09;&#xff1a; 代码&#xff1a; 例题&#xff1a;快速幂求逆元 作用&#xff1a; 快速求出 的结果。 时间复杂度&#xff1a; O(logk) 如果使用一般做法&#xff0c;从1循环到k&#xff0c;时间复杂度是O(k) 反复平方法&am…