C++ 动态内存管理

news2024/11/29 6:24:43

目录

1. C/C++内存分布

练习

2. C语言中动态内存管理方式:malloc/calloc/realloc/free

3. C++内存管理方式

3.1 new/delete操作内置类型

 3.2 new和delete操作自定义类型

4. operator new与operator delete函数

4.1 operator new与operator delete函数(重点)

5. new和delete的实现原理

5.1 内置类型

5.2 自定义类型

6.定位new(placement-new) 

7. 常见面试题

7.1 malloc/free和new/delete的区别

7.2 内存泄漏

7.2.1 什么是内存泄漏,内存泄漏的危害

7.2.2 内存泄漏分类

7.2.4如何避免内存泄漏


1. C/C++内存分布

下图中的内存区域划分是指:虚拟内存的划分

内核空间用户不能操作的,内核空间之外的才是用户空间

局部变量都存在栈帧中,下图中浅蓝色框

常量字符串不能被修改,所以放在代码段

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

练习

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在哪里?   C
staticVar在哪里?   C
localVar在哪里?    A
num1 在哪里? A
char2在哪里? A
*char2在哪里?D
pChar3在哪里? A
*pChar3在哪里? D
ptr1在哪里?  A
 *ptr1在哪里?B
2. 填空题:
sizeof ( num1 ) = _40___ ;
sizeof ( char2 ) = __5__ ; strlen ( char2 ) = __4__ ;
sizeof ( pChar3 ) = __4__ ; strlen ( pChar3 ) = _4___ ;
sizeof ( ptr1 ) = __4__ ;
注意:sizeof求的是类型的大小,strlen求字符串有效长度,不算/0

2. C语言中动态内存管理方式:malloc/calloc/realloc/free

这部分内容可以在之前的博客中学习复习

C语言动态内存管理

3. C++内存管理方式

C 语言内存管理方式在 C++ 中可以继续使用,但有些地方就无能为力,因此 C++ 又提出了自己的内存管理方式: 通过new和delete操作符进行动态内存管理
为什么C++没有继续使用malloc和free?
原因:C++是基于面向对象的程序设计而言,C语言中的malloc只负责从堆上申请空间,并不会调用构造方法对对象空间进行初始化
free只负责将堆空间释放掉,在释放时并不会调用析构函数清理对象当中的资源
new:在申请空间之后,也会调用构造方法将空间中的内容初始化好
delete:在释放空间之前,也会调用析构函数将对象中的资源清理掉

3.1 new/delete操作内置类型

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

注意:申请和释放单个元素的空间,使用 new和delete 操作符,申请和释放连续的空间, 使用 new[ ]和 delete[ ] 注意:匹配起来使用,负责会造成内存泄漏或者程序崩溃。

 3.2 newdelete操作自定义类型

new/delete malloc/free 最大区别是 new/delete 对于【自定义类型】除了开空间还会调用构
造函数和析构函数
注意:在申请自定义类型的空间时, new 会调用构造函数, delete 会调用析构函数,而 malloc free 不会

4. operator newoperator delete函数

4.1 operator newoperator delete函数(重点

new delete 是用户进行 动态内存申请和释放的操作符 operator new operator delete 是系统提供的 全局函数 new 在底层调用 operator new 全局函数来申请空间, delete 在底层通过 operator delete 全局函数来释放空间
operator new 实际也是通过malloc来申请空间
如果malloc申请空间成功就直接返回
否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。
operator delete 最终是通过free来释放空间的
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
 // try to allocate size bytes
 void *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_FINALLY
  return;
}

2.如果T是自定义的类型,还需要调用T类中对应方法的构造方法,对申请空间中的内容进行初始化。

5. newdelete的实现原理

5.1 内置类型

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

5.2 自定义类型

new的原理
1. 调用operator new函数申请空间
2. 在申请的空间上执行构造函数,完成对象的构造
new的实现方式:  T* p = new T;
调用 void* operator new(size_t size/*size要申请空间总的字节数*/)负责申请空间
注意:该方法需要的参数是编译器编译阶段根据new之后的类型确定下来的

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

new T[N]的原理
1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申
2. 在申请的空间上执行N次构造函数
delete[ ]的原理
1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

6.定位new(placement-new) 

定位 new 表达式是在 已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表
使用场景:
定位 new 表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new 的定义表达式进行显示调构造函数进行初始化

7. 常见面试题

7.1 malloc/freenew/delete的区别

malloc/free 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 在释放空间前会调用析构函数完成空间中资源的清理

7.2 内存泄漏

7.2.1 什么是内存泄漏,内存泄漏的危害

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死

7.2.2 内存泄漏分类

C/C++ 程序中一般我们关心两种方面的内存泄漏:
堆内存泄漏(Heap leak)
堆内存指的是程序执行中依据须要分配通过 malloc / calloc / realloc / new 等从堆中分配的一块内存, 用完后必须通过调用相应的 free 或者 delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak
系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
vs 下,可以使用 windows 操作系统提供的 _CrtDumpMemoryLeaks() 函数进行简单检测,该函数只报出了大概泄漏了多少个字节,没有其他更准确的位置信息

7.2.4如何避免内存泄漏

1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。 ps :这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
2. 采用 RAII 思想或者智能指针来管理资源。
3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
4. 出问题了使用内存泄漏工具检测。 ps :不过很多工具都不够靠谱,或者收费昂贵。
总结一下 :
内存泄漏非常常见,解决方案分为两种: 1 、事前预防型。如智能指针等。 2 、事后查错型。如泄漏检测工具

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

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

相关文章

跨境多账号管理教程分享:解决多账号管理混乱问题

如今,跨境电商卖家拥有多平台多账号已经成为常态,但很多人找东哥咨询的担忧都是要如何有效地管理这么多账号,因为如果账号过多,容易被关联,进而影响账号安全。如果你也刚好有这个烦恼,那找东哥真的就是找对…

HEVC 编码速率控制

视频传输带宽通常都会受到一定的限制,为了在满足通信带宽和传输时延限制的情况下有效传输视频数据,保证视频业务的播放质量,需要对视频编码过程进行速率控制,所谓速率控制,就是通过选择一系列编码失真尽量小&#xff0…

「TCG 规范解读」初识 TPM 2.0 库续三

可信计算组织(Ttrusted Computing Group,TCG)是一个非盈利的工业标准组织,它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立,并采纳了由可信计算平台联盟(the Trusted Computing Platform Alli…

导航定位状态评估专题:“特征”离群点判断与剔除 | 定位状态完整性监控

1、前言:经典状态估计中协方差的计算能准确反映机器人状态的完整性吗?在每一次机器人执行各种目的的自动导航任务时,拥有高精度且可靠状态估计的能力可以说是机器人顺利、安全完成任务的必要条件之一。简而言之,机器人状态估计算法…

Docker Compose

为什么需要使用Docker ComposeDocker Compose 容器编排技术1、现在我们有一个springboot项目,需要依赖Redis、mysql、nginx。如果使用docker原生部署的话,则需要安装Redis、mysql、nginx容器,才可以启动我们springboot项目,这样的…

Flink-CEP理论与实践

一.什么是Flink cepCEP 是复杂事件处理(Complex Event Processing)的缩写,是一种处理实时数据流的技术。它可以在大规模数据流中实时识别出与预定义的模式匹配的事件,并在匹配到事件时采取相应的措施。CEP 技术的应用范围非常广泛…

Web前端:为什么要雇佣全栈开发人员

全栈开发人员是任何软件开发项目的宝贵专家。但是,在某些情况下,它们是企业最需要的。雇佣一名全栈开发人员来监督你的项目,从构思到启动,再到以后,有无数的好处。1.出色的web/应用程序开发人员全栈web开发人员有经验&…

CSS3实现文字循环滚动播放

CSS3实现文字循环滚动播放 效果图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&q…

【微信小程序】-- 常用视图容器类组件介绍 -- view、scroll-view和swiper(六)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#…

分布式爬虫的介绍和搭建

分布式爬虫 Scrapy单机模式 Scrapy引擎通过一调度器&#xff0c;将request队列中的 request请求发给下载器进行页面的爬取 Scrapy单机框架的优缺点 优点&#xff1a; 部署容易&#xff0c;架构简单快速&#xff0c;快速部署 缺点&#xff1a; 单点执行&#xff0c;抓取…

假脱机技术Spooling和守护进程

文章目录假脱机系统Spooling和守护进程1.假脱机技术的引入2.SPOOling系统的组成3.SPOOling系统的工作过程守护进程假脱机系统Spooling和守护进程 1.假脱机技术的引入 脱机技术&#xff1a; 为了缓和CPU的高速性与IO设备的低速性间的矛盾&#xff0c;而引入了脱机输入&#xf…

Objective-C 中类和对象的基本使用 方法的调用(消息传递)

总目录 iOS开发笔记目录 从一无所知到入门 文章目录Intro截图自定义类型的interface部分和implementation部分main方法中的类型调用部分Demo测试代码输出Intro Objective-C&#xff0c;具有面向对象特性的C。 但其实&#xff0c;它的面向对象和其他高级语言相比&#xff0c;还…

【C++】C++的内存模型之四大分区

程序的内存模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的全局区&#xff1a;存放全局变量和静态变量以及常量栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值&…

CIMCAI intelligent tally shore AI auto container damage detect

全球港航人工智能/集装箱人工智能领军者CIMCAI&#xff0c;世界首创港口岸边超级智能理货产品自动化AI验箱&#xff0c;AI自动化码头港口数字化港口。中集飞瞳CIMCAI领跑全球港口码头人工智能科技&#xff0c;领先集装箱箱况残损识别科技全方位提升港口码头效能。集装箱残损可能…

剑指 Offer 68 - I. 二叉树的最近公共祖先

摘要 剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 剑指 Offer 68 - II. 二叉树的最近公共祖先 一、二叉搜索树的最近公共祖先 注意到题目中给出的是一棵二叉搜索树&#xff0c;因此我们可以快速地找出树中的某个节点以及从根节点到该节点的路径&#xff0c;例如我们需要找…

2023年金三银四必备软件测试常见面试题1500问!!!

十九、持续集成19.1 jenkins ant jmeter svn接口自动化测试?jenkins ant jmeter svn环境搭建原来这个环境是我这边搭建的&#xff0c;主要是几个步骤&#xff0c;第一Jenkins安装、第二&#xff0c;ant安装、第三&#xff0c;jmeter安装、第四&#xff0c;jmeter与ant连…

HTML基础(1)

HTML基础HTML基本介绍编辑工具HTML概述多如牛毛的标签头部标签&#xff1a;标题与段落标签&#xff1a;br换行符&#xff1a;a href超链接标签&#xff1a;< meta > 元素标签&#xff1a;主体标签HTML注释&#xff1a;水平线标签hr&#xff1a;段落标签p&#xff1a;文本…

[ 常用工具篇 ] 多媒体视频处理工具 ffmpeg 安装使用详解

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

【python学习笔记】:字符串编码转换

在 Python 中&#xff0c;有 2 种常用的字符串类型&#xff0c;分别为 str 和 bytes 类型&#xff0c;其中 str 用来表示 Unicode 字符&#xff0c;bytes 用来表示二进制数据。str 类型和 bytes 类型之间就需要使用 encode() 和 decode() 方法进行转换。 Python encode()方法 …

软件工程(4)--螺旋模型

前言 这是基于我所学习的软件工程课程总结的第四篇文章。 在软件开发过程中必须及时识别和分析风险&#xff0c;并且采取适当措施以消除或减少风险的危害。构建原型是一种能使某些类型的风险降至最低的方法。为了降低交付给用户的产品不能满足用户需要的风险&#xff0c;一种行…