【C++语言】C/C++内存管理

一、C/C++内存分布

       我们先来看一看C/C++中有哪些区域,为什么C/C++中区分这些区域呢??不同的数据有不同的存储需求,各个区域满足不同的需求。我们有临时用的数据,该数据是存储在栈帧区域的;在一些数据结构中,算法中需要动态开辟一些空间,比如:归并排序,这些数据是存储在堆区的;在整个程序期间都要使用的数据,我们称之为只读数据,像全局数据、静态数据存储在静态区中,像可执行代码和只读常量存储在常量区中。

我们下面来总结一下:

  1. 栈又叫做堆栈——非静态局部变量/函数参数/返回值等等,栈是向下增长的
  2. 内存映射段是高效的I/O映射方式,用于装载到一个共享的动态内存库,用户可以使用系统接口创建共享内存,进行进程间通信
  3. 堆用于程序运行时动态内存分配,堆是可以向上增长的
  4. 数据段(静态区)——存储全局数据和静态数据
  5. 代码段(常量区)——可执行的代码和只读常量

1.2 练习习题

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在哪里?  全局变量,在静态区  C
  • staticGlobalVar在哪里? 全局变量,用static修改,静态变量,在静态区 C
  • staticVar在哪里?  用static修饰,静态变量,但是作用范围被限制在函数中  在静态区 C
  • localVar在哪里?  局部变量,在栈区  A
  • num1 在哪里?  局部变量,在栈区  A
  • char2在哪里?  局部变量,在栈区开辟数组,在栈区  A
  • *char2在哪里?  局部变量,指针指向的地方在栈区 A
  • pChar3在哪里?  数组指针,局部变量,在栈区 A
  • *pChar3在哪里?  字面值常量,只读常量,在常量区  D
  • ptr1在哪里?  指针,局部变量,在栈区  A
  • *ptr1在哪里?  利用malloc函数开辟空间,在堆区  B

填空题:

  • sizeof(num1) =  40
  • sizeof(char2) =  5
  • strlen(char2) =  4
  • sizeof(pChar3) =  4/8
  • strlen(pChar3) =  4
  • sizeof(ptr1) =  4/8

二、C++内存管理方式

       C语言内存管理方式在C++中可以继续使用,但是在有些地方就无能为力了,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符来进行动态内存管理

2.1 new/delete操作内置类型

void Test()
{// 动态申请一个int类型的空间int *ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int *ptr5 = new int(10);// 动态申请10个int类型的空间int *ptr6 = new int[10];delete ptr4;delete ptr5;delete[] ptr6;
}

 

       注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意,要进行匹配使用

2.2 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不会。

三、operator new 和 operator delete 函数

       new和delete函数是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层调用operator delete全局函数来释放空间。

       我们来看一下这两个函数在底层是如何封装的?我们在C语言中使用malloc函数和free函数来封装operator new 和 operator delete函数,接下来,我们来看一看底层的代码:

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid *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来释放空间的。

       为什么我们要重新封装一下malloc函数呢??因为C++语言是面向对象的语言,但是之前的malloc是C语言的,不具有面向对象的思想。因为malloc在创建空间失败后,我们需要抛出一个异常,但是malloc函数本身是返回0,所以我们需要将malloc函数重新封装满足我们面向对象的思想。封装free函数其实没有什么,为了对称,我们需要进行重新封装free函数。

我们在使用这些函数,我们需要进行配对使用,如果我们将类中的析构函数进行注释,(这里有一些重点)

四、new和delete的实现原理

4.1 内置类型

       如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方在于:new/delete申请和释放的是单个元素的空间,new[] 和 delete[] 申请的是连续的空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

4.2 自定义类型

new的原理:

  • 调用operator new函数申请空间
  • 在申请的空间上执行构造函数,完成对象的构造

delete的原理:

  • 在空间上执行析构函数,完成对象中资源的清理工作
  • 调用operator delete函数释放对象的空间

new T[N] 的原理:

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

delete[] 的原理:

  • 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  • 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

五、定位new表达式

定位new表达式是在已经分配的原始内存空间中调用构造函数初始化一个对象。

使用的格式是:

new(place_address)type 或者 new(place_address)type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表

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

六、常见的面试题

6.1 malloc/free 和 new/delete 的区别(从用法和原理上分析)

       malloc/free 和 new/delete 的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:

  • malloc和free是函数,new和delete是操作符
  • malloc申请的空间不会初始化,new可以进行初始化
  • malloc申请空间时,需要手动计算空间大小并传递,new只需在其后面跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可
  • malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常

       申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数和析构函数,而在new申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

6.2 内存泄露

6.2.1 什么是内存泄露,内存泄露的危害

       什么是内存泄露:内存泄露指的是因为疏忽或者错误造成程序未能释放已经不再使用的内存的情况。内存泄露并不是指的是内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

       内存泄露的危害:长期运行的程序出现内存泄露,影响很大,比如操作系统,后台服务等等,出现内存泄露会导致响应越来越慢,最终卡死。

6.2.2 内存泄露分类(了解)

C/C++程序中一般我们关心两种方面的内存泄露:

堆内存泄露

       堆内存指的是程序执行中依据需要分配通过malloc/calloc/realloc/new等从堆中分配的一块内存,用完后必须通过调用相应的free或者delete删除。假设程序的设计错误导致这部分的内存没有被释放,那么以后这部分的空间将无法再次使用,就会产生Heap Leak。

系统资源泄露

       这种情况指的是程序使用系统分配的资源,比如套接字,文件描述符,管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可以导致系统效能减少,系统执行不稳定。

6.2.3 如何检测内存泄露(了解)

       在VS下,可以使用windows操作系统提供的_CrtDumpMemoryLeaks()函数进行简单检测,该函数只报出了大概率泄露了多少个字节,没有其他更准确的位置信息。

int main()
{int* p = new int[10];// 将该函数放在main函数之后,每次程序退出的时候就会检测是否存在内存泄漏_CrtDumpMemoryLeaks();return 0;
}// 程序退出后,在输出窗口中可以检测到泄漏了多少字节,但是没有具体的位置
Detected memory leaks!
Dumping objects ->
{79} normal block at 0x00EC5FB8, 40 bytes long.Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

6.2.4 如何避免内存泄露

  1. 工程前期良好的设计规范,养成了良好的编码规范,申请的内存空间记着匹配的去释放,(这个理想状态,但是如果碰上异常时,就算注意释放了,还是可能会出现问题。需要下一条智能指针来管理才有保证)
  2. 采用RAII思想或者智能指针来管理资源
  3. 有些公司内部规范使用内部实现的私有内存管理库,这些库自带内存泄露检测的功能选项
  4. 出问题了使用内存泄露工具检测(不过很多工具不靠谱)

总结一下:

内存泄露非常常见,解决方案分为两种:

  1. 事前预防型,比如智能指针等
  2. 事后查错型,比如泄露检测工具

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

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

相关文章

自媒体起号新思路!利用AI创作治愈类内容的运营指南

最近&#xff0c;治愈类内容在各大社交平台上备受欢迎。无论是刷短视频还是看小红书&#xff0c;都能发现这类账号的流量巨大&#xff0c;粉丝数量飞速增长。 总而言之&#xff0c;汇成一句话&#xff1a; 如何利用AI技术&#xff0c;创作治愈类的图片和视频&#xff0c;吸引粉…

JavaEE:网络初识

文章目录 网络初识网络中的重要概念IP地址端口号认识协议(最核心概念)OSI七层模型TCP/IP五层(或四层)网络模型网络设备所在分层封装和分用 网络初识 网络中的重要概念 网络互联的目的是进行网络通信,也是网络数据传输,更具体一点,是网络主机中的不同进程间,基于网络传输数据.…

html,css基础知识点笔记(二)

9.18&#xff08;二&#xff09; 本文主要教列表的样式设计 1&#xff09;文本溢出 效果图 文字限制一行显示几个字&#xff0c;多余打点 line-height: 1.8em; white-space: nowrap; width: 40em; overflow: hidden; text-overflow: ellipsis;em表示一个文字的大小单位&…

计算机人工智能前沿进展-大语言模型方向-2024-09-18

计算机人工智能前沿进展-大语言模型方向-2024-09-18 1. The Application of Large Language Models in Primary Healthcare Services and the Challenges W YAN, J HU, H ZENG, M LIU, W LIANG - Chinese General Practice, 2024 人工智能大语言模型在基层医疗卫生服务中的应…

【Delphi】知道控件名称(字符串),访问控件

在 Delphi 中&#xff0c;可以使用 RTTI&#xff08;运行时类型信息&#xff09; 或其他方法通过对象的名称字符串来访问对象。比如&#xff0c;如果你有一个控件的名称字符串&#xff0c;你希望通过该名称找到并访问实际的控件。 以下是通过 RTTI 以及其他技术&#xff08;如…

SAP B1 单据页面自定义 - 用户界面编辑字段

背景 接《SAP B1 基础实操 - 用户定义字段 (UDF)》&#xff0c;在设置完自定义字段后&#xff0c;如下图&#xff0c;通过打开【用户定义字段】可打开表单右侧的自定义字段页。然而再开打一页附加页面操作繁复&#xff0c;若是客户常用的定义字段&#xff0c;也可以把这些用户…

图片类型转化---模拟某wps

文件上传功能的深入探讨 文件上传是Web应用程序中常见的功能&#xff0c;它允许用户将本地文件通过Web界面发送到服务器。在Flask中&#xff0c;这通常是通过处理表单数据来实现的。表单必须设置enctype为multipart/form-data&#xff0c;这样浏览器才能将文件作为多部分消息发…

GitLab CI_CD 从入门到实战笔记

第1章 认识GitLab CI/CD 1.3 GitLab CI/CD的几个基本概念 GitLab CI/CD由以下两部分构成。 &#xff08;1&#xff09;运行流水线的环境。它是由GitLab Runner提供的&#xff0c;这是一个由GitLab开发的开源软件包&#xff0c;要搭建GitLab CI/CD就必须安装它&#xff0c;因…

实战分享:我是如何挖到CSDN漏洞的?

文章目录 前言一、过程二、总结《Windows信息安全和网络攻防》——清华大学出版社 前言 CxxN是国内很出名的博客平台&#xff0c;用户量非常大&#xff0c;注册用户据说有1个亿&#xff1f;(官方写的)本次我发现的漏洞详情是可以通过用户的id直接获取用户完整的手机号&#xf…

【深度学习】(2)--PyTorch框架认识

文章目录 PyTorch框架认识1. Tensor张量定义与特性创建方式 2. 下载数据集下载测试展现下载内容 3. 创建DataLoader&#xff08;数据加载器&#xff09;4. 选择处理器5. 神经网络模型构建模型 6. 训练数据训练集数据测试集数据 7. 提高模型学习率 总结 PyTorch框架认识 PyTorc…

第二届”青春同行 共享未来“两岸新媒体创享活动在京开启

9月6日&#xff0c;第二届“青春同行 共享未来”两岸新媒体创享活动在北京盛大开启。本次活动旨在促进两岸青年文化交流与合作&#xff0c;共同探索新媒体时代两岸文化与经济的创新与发展新路径。爱迪斯通董事长吴明勳先生作为特邀嘉宾出席活动并发表演讲&#xff0c;在演讲中吴…

RK3568部署DOCKER启动服务器失败解决办法

按照上文的方法部署完DOCKER之后&#xff0c;启动服务异常&#xff0c;查阅网络相关资源&#xff0c;解决方案如下&#xff1a; 修改/源码/kernel/arch/arm64/configs/OK3568-C-linux_defconfig&#xff0c;在最后添加 CONFIG_MEMCGy CONFIG_VETHy CONFIG_BRIDGEy CONFIG_BRID…

算法训练——day16快乐数

202. 快乐数 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结果为…

2024年 现象级的商业模式 上海某店!为何能火爆出圈!

大家好&#xff0c;我是吴军&#xff0c;目前在一家备受瞩目的软件开发公司担任产品管理的重要角色。 当前&#xff0c;市场正经历着商业模式的深刻变革&#xff0c;一种创新的商业模式如潮水般涌现&#xff0c;它巧妙地为消费者编织了省钱的网络&#xff0c;同时也为商家铺设了…

软考架构-面向服务的架构风格

一、SOA 1、概念 面向服务开发&#xff0c;服务之间通过简单、精确定义接口进行通信&#xff0c;不涉及底层编程接口和通信模型。多个服务挂载在ESB&#xff08;企业服务总线&#xff09;上进行通信。 2、特征 可从企业外部访问、随时可用&#xff08;服务请求能被及时响应…

比较推荐哪种可视耳勺?市场高口碑可视耳勺推荐!

很多人仍在使用棉签或者传统金属挖耳勺进行耳部清洁&#xff0c;但往往会清洁不干净或者操作失误引发意外。今天小编要给大家介绍一款新型的挖耳工具---可视耳勺&#xff0c;它能通过内置摄像头进入耳朵查看耳朵内部情况&#xff0c;看清楚耳垢的位置&#xff0c;能清洁干净耳朵…

saltstack高级用法

一、saltstack的高级用法 一、job管理 1、job简介 Jid&#xff1a;job id&#xff0c;格式为%Y%m%d%H%M%S%fmaster在下发指令消息时&#xff0c;会附带上产生的Jid&#xff0c;minion在接收到指令开始执行时&#xff0c;会在本地的cachedir&#xff08;默认是/var/cache/salt/…

人工智能开发实战matplotlib库应用基础

内容导读 matplotlib简介绘制直方图绘制撒点图 一、matplotlib简介 matplotlib是一个Python 2D绘图库&#xff0c;它以多种硬拷贝格式和跨平台的交互式环境生成高质量的图形。 matplotlib 尝试使容易的事情变得更容易&#xff0c;使困难的事情变得可能。 我们只需几行代码…

C语言深入理解指针(二)

目录 指针运算指针-整数指针-指针指针的关系运算 野指针野指针成因指针未初始化指针越界访问指针指向的空间释放 如何规避野指针指针初始化注意指针越界指针不使用时就用NULL避免返回局部变量的地址 assert断言指针的使用和传址调用传址调用例子&#xff08;strlen函数的实现&a…

SSC338D/SSC338Q CA7*2+IPU5M/Multi-sensorISP: HDR/3DNR

SSC338D/SSC338Q系列产品是高度集成的多媒体片上系统&#xff08;SoC&#xff09;产品&#xff0c;适用于IP摄像机、车载摄像机和USB摄像机等高分辨率智能视频录制应用。该芯片包括32位双核RISC处理器、高级图像信号处理器&#xff08;ISP&#xff09;、高性能MJPEG/H.264/H.26…