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.hqwc.cn/news/512533.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【HarmonyOS】鸿蒙开发之Stage模型-组件生命周期——第4.4章

组件生命周期简介 组件生命周期包括&#xff1a;onPageShow,onPageHide,onBackPress,aboutToAppear,aboutToDisappear五个状态。流程如下图: 注意:以下展示的生命周期钩子都是被Entry装饰器装饰的组件生命周期 onPageShow&#xff1a;页面每次显示时触发。onPageHide&#xf…

[MRCTF2020]Transform1

a[33]"9,10,15,23,7,24,12,6,1,16,3,17,32,29,11,30,27,22,4,13,19,20,21,2,25,5,31,8,18,26,28,14" b[33]"103,121,123,127,117,43,60,82,83,121,87,94,93,66,123,45,42,102,66,126,76,87,121,65,107,126,101,60,92,69,111,98,77" python代码 a3 [103…

【pyinstaller打包记录】Linux系统打包可执行文件后,onnxruntime报警告(Init provider bridge failed)

简介 PyInstaller 是一个用于将 Python 程序打包成可执行文件&#xff08;可执行程序&#xff09;的工具。它能够将 Python 代码和其相关的依赖项&#xff08;包括 Python 解释器、依赖的模块、库文件等&#xff09;打包成一个独立的可执行文件&#xff0c;方便在不同环境中运行…

【如何在Docker中,修改已经挂载的卷(Volume)】

曾梦想执剑走天涯&#xff0c;我是程序猿【AK】 提示&#xff1a;添加投票&#xff01;&#xff01;&#xff01; 目录 简述概要知识图谱 简述概要 如何在Docker中&#xff0c;修改已经挂载的卷&#xff08;Volume&#xff09; 知识图谱 在Docker中&#xff0c;修改已经挂载…

HI3516DV300 HI3516DRBCV300 海思安防监控芯片

Hi3516D V300是专为行业专用智能高清网络摄像机设计的新一代SoC。引入新一代ISP、最新H.265视频压缩编码器、高性能NNIE引擎&#xff0c;使Hi3516D V300在低码率、高图像质量、智能处理分析、低功耗等方面领先业界。能量消耗。Hi3516D V300集成了POR、RTC、音频编解码器和待机唤…

【Gitee】创建第一个仓库并提交第一次代码

目录 第一步&#xff1a;注册登录 第二步&#xff1a;创建第一个仓库 1、我的工作台 → 创建我的仓库 2、填写内容 3、创建 第三步&#xff1a;第一次提交代码 1、参考资料 2、操作 2.1 idea创建项目 2.2 项目内容推送至远程 最后&#xff1a;平台相关资料库 第一步…

⭐北邮复试刷题2369. 检查数组是否存在有效划分__DP (力扣每日一题)

2369. 检查数组是否存在有效划分 给你一个下标从 0 开始的整数数组 nums &#xff0c;你必须将数组划分为一个或多个 连续 子数组。 如果获得的这些子数组中每个都能满足下述条件 之一 &#xff0c;则可以称其为数组的一种 有效 划分&#xff1a; 子数组 恰 由 2 个相等元素…

java核心面试题汇总

文章目录 1. Java1.1. TCP三次握手/四次挥手1.2 HashMap底层原理1.3 Java常见IO模型1.4 线程与线程池工作原理1.5 讲一讲ThreadLocal、Synchronized、volatile底层原理1.6 了解AQS底层原理吗 2. MySQL2.1 MySQL索引为何不采用红黑树&#xff0c;而选择B树2.2 MySQL索引为何不采…

户外、春衣、养发……阿里妈妈经营指南揭秘38消费热点

在春天这个万象更新的季节&#xff0c;春天生意也在升温。 内容平台上&#xff0c;#成都醉美樱花季 #春天穿什么 互动增长率分别达到了156倍、252倍&#xff1b;#初春氛围感穿搭 #春游记 的互动增长率分别达到了77倍、24倍……“赏花”“穿搭”“居家锻炼”等和春天有关的消费…

win11下安装mysql

一、下载MySQL 官方下载传送门 我安装的版本是5.7.83 二、安装MySQL 1.双击安装包 2.选择Custom(自定义安装)&#xff0c;然后Next> 3.根据你的系统做选择&#xff0c;我的是64位&#xff0c;所选MySQL Servers 5.7.38 -x64&#xff0c;然后按箭头将选中的版本移到右边…

在美创科技收到的这一封感谢信的背后

2月20日&#xff0c;美创科技收到了一份特殊的“新年开工礼包”——来自复旦大学附属中山医院的感谢信&#xff0c;让我们倍受鼓舞&#xff0c;一段数据安全“并肩协作”的故事也再次浮现。 复旦大学附属中山医院&#xff08;以下简称“中山医院”&#xff09;始建于1937年&…

MongoDB快速⼊⻔【简介、基本操作、索引、执行计划、UI客户端工具、SpringBoot整合MongoDB】

MongoDB快速⼊⻔ MongoDB简介通过docker安装MongoDBMongoDB基本操作基本概念数据库以及表的操作新增数据更新数据删除数据查询数据 索引执⾏计划UI客户端⼯具 SpringBoot整合MongoDB 转自 黑马 MongoDB简介 通过docker安装MongoDB MongoDB基本操作 基本概念 数据库以及表的操…