【C++】内存管理

目录

C/C++内存分布

C语言中动态内存管理方式

C++内存管理方式

operator new与 operator delete函数

匹配使用的相关问题-内存泄漏:

delete与delete [ ]

malloc/free和 new/delete的区别

内存泄漏


C/C++内存分布

  1. 又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口 创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)

  3. 用于程序运行时动态内存分配,堆是可以上增长的。

  4. 数据段--存储全局数据和静态数据。

  5. 代码段--可执行的代码/只读常量

C语言中动态内存管理方式

具体讲解:C语言:动态内存管理(动态内存+柔性数组讲解)_努力学c的楼下小王的博客-CSDN博客

int * p1=(int*)malloc(sizeof(int));
if(p1==NULL)
{perror("malloc is fail");
}
free(p1);

C++内存管理方式

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

注意:申请和释放单个元素的空间,使用new和delet操作符,申请和释放连续的空间,使用new[]delete[],注意:匹配起来使用。 也切勿使用C语言中的free或malloc等与C++中的new和delete交叉使用 否则导致结果是不确定的

operator new与 operator delete函数

注意! 此处的operator 并不是函数重载,而是库函数

operator new与 operator delete本质上是malloc和free的封装

operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间 失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否 则抛异常。

operator delete: 该函数最终是通过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)


 int main(){//申请失败会抛出异常int *p1 = (int *)operator new(sizeof(int *));//失败返回nullptrint *p2 = (int *)malloc(sizeof(int *));if (p2 == NULL){perror("malloc is fail");}​return 0;}
 // 申请空间 operator nwe -> 封装malloc// 调用构造函数A *p3 = new A;​// 先调用析构函数,在释放p3指向的空间delete p3;​// 申请空间: operator new[]-> operator new -> malloc封装A *p4 = new A[10];​// 先调用10次析构函数,在释放p4指向的空间delete[] p4; //[]只是为了匹配
匹配使用的相关问题-内存泄漏:

由前文可知,C++中的new与delete和C中的mlloc.. 和free尽量不要交叉使用 看下列代码:

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

此处并没有报错,若是使用delete p2时,则会先调用析构函数再进行free

而此处直接使用free 释放,释放的是堆上的空间,但少调用了析构函数, 但此处也无需调用析构函数,A类中并没有额外的资源需要进行清理, 若是A类中有需要额外清理的则会导致内存泄漏如:

 class Stack{private:int* _a;int _size;int _capacity;​public:Stack(){cout << "Stack():" << this << endl;_a=new int[4];_size=0;_capacity =4;}​~Stack(){cout << "~Stack():" << this << endl;delete[] _a;_size=_capacity=0;}};​int main(){//st为自定义类型,出了函数会自动调用析构函数Stack st;​//pst为指针,是内置类型,不会自动调用Stack* pst=new Stack;delete pst;​return 0;}

由上图可以看出,pst必须先调用析构函数将堆中创建的空间进行销毁:

调用完析构函数后,再调用operator delete(pst):

若此时使用的是free(pst): 则导致无法调用析构函数,无法释放空间,而pst指针指向的空间被销毁,而之前通过 new 分配的内存将无法被正确释放导致内存泄漏

结论:new/malloc系列 底层实现机制有关联交叉.不匹配使用,可能有问题,也可能没问题

delete与delete [ ]

部分编译器会实现该机制或不同编译器实现机制不同

 int main(){A* p1=new A[10];delete[] p1;​return 0;}

编译器会在头部多开4字节,存储数组元素个数,用于delete,使编译器知道要调用多少次析构函数(此处地址为p1地址-4字节):

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

内存泄漏

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

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

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

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

相关文章

mfc140u.dll丢失的解决方法,以及针对每个解决mfc140u.dll丢失办法的优缺点

在使用电脑的过程中&#xff0c;有时会遇到一些与动态链接库文件&#xff08;DLL&#xff09;相关的错误。其中&#xff0c;mfc140u.dll丢失是一种常见的问题&#xff0c;它可能导致应用程序无法正常运行。在本文中&#xff0c;我们将探讨关于mfc140u.dll丢失的解决办法&#x…

openGauss通过VIP实现的故障转移

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

【Linux】进程间是这样通信的--管道篇

TOC 目录 进程间通信的介绍 进程间通信的概念 进程间通信的目的 进程间通信的本质 进程间通信的分类 管道 什么是管道 匿名管道 pipe函数 匿名管道使用步骤 管道读写规则 管道的特点 1、管道内部自带同步与互斥机制 2、管道的生命周期随进程 3、管道提供的是流式…

【PyQt小知识 - 2】:QTextEdit内容的更新和获取、隐藏或显示滚动条、光标插入文本、文本自适应移动

文章目录 QTextEdit更新和获取内容隐藏或显示滚动条光标插入文本文本自适应移动 QTextEdit 更新和获取内容 更新&#xff1a;QTextEdit().setText(text) 或 QTextEdit().setPlainText(text) 获取&#xff1a;QTextEdit().toPlainText() setText()和setPlainText()的区别&…

UiPath Studio 2023.10 Crack

UiPath Studio是一款功能强大且用户友好的集成开发环境 (IDE)&#xff0c;专为机器人流程自动化 (RPA) 设计。它由自动化技术领域的领先公司UiPath开发。 以下是 UiPath Studio 的一些主要功能和组件&#xff1a; 图形用户界面 (GUI)&#xff1a;UiPath Studio 具有直观且用户友…

力扣每日一题-数位和相等数对的最大和-2023.11.18

力扣每日一题&#xff1a;数位和相等数对的最大和 开篇 这道每日一题还是挺需要思考的&#xff0c;我绕晕了好久&#xff0c;根据题解的提示才写出来。 题目链接:2342.数位和相等数对的最大和 题目描述 代码思路 1.创建一个数组存储每个数位的数的最大值&#xff0c;创建一…

LabVIEW关于USRPRIO的示例代码

LabVIEW关于USRPRIO的示例代码 USRPRIO 通常以两种方式使用&#xff1a; 1 基于 FPGA 的编程 对于希望修改USRP上的底层FPGA代码以添加自定义DSP模块的应用&#xff0c;请使用USRP示例项目。它可作为构建 USRP RIO 流式处理应用程序的起点&#xff0c;可从“创建项目”对话框…

Linux进程——exec族函数、exec族函数与fork函数的配合

exec族函数解析 作用 我们用fork函数创建新进程后&#xff0c;经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时&#xff0c;该进程被完全替换为新程序。因为调用exec函数并不创建新进程&#xff0c;所以前后进程的ID并没有改变。 功能 在调用进程内部…

十. Linux关机重启命令与Vim编辑的使用

关机重启命令 shutdown命令 其他关机命令 其他重启命令 系统运行级别 系统默认运行级别与查询 退出登录命令logout 文本编辑器Vim Vim简介 没有菜单,只有命令Vim工作模式 Vim常用命令 插入命令 定位命令 删除命令 复制和剪切命令 替换和取消命令 搜索和搜索替换命令 保存和退出…

2023 PostgreSQL 数据库生态大会:解读拓数派大数据计算系统及其云存储底座

11月3日-5日&#xff0c;由中国开源软件推进联盟 PostgreSQL 分会主办的中国 PostgreSQL 数据库生态大会在北京中科院软件所隆重举行。大会以”极速进化融合新生”为主题&#xff0c;从线下会场和线上直播两种方式展开&#xff0c;邀请了数十位院士、教授、高管和社群专家&…

AIGC 是通向 AGI 的那条路吗?

AIGC 是通向 AGI 的那条路吗&#xff1f; 目录 一、背景知识 1.1、AGI&#xff08;人工通用智能&#xff09; 1.1.1、概念定义 1.1.2、通用人工智能特质 1.1.3、通用人工智能需要掌握能力 1.2、AIGC 二、AIGC 是通向 AGI 的那条路吗&#xff1f; 三、当前实现真正的 A…

Windows server 2012 R2系统服务器远程桌面服务激活服务器RD授权分享

Windows server 2012 R2系统服务器远程桌面服务激活服务器RD授权 二、激活服务器&#xff0c;获取许可证服务器ID和许可证密钥包ID三、激活终端服务器四、配置远程桌面会话主机授权服务器 上期我分享了Windows server 2012 R2系统服务器远程桌面服务的安装教程&#xff0c;若是…

redis运维(十一) python操作redis

一 python操作redis ① 安装pyredis redis常见错误 说明&#xff1a;由于redis服务器是5.0.8的,为了避免出现问题,默认最高版本的即可 --> 适配 ② 操作流程 核心&#xff1a;获取redis数据库连接对象 ③ Python 字符串前面加u,r,b的含义 原因&#xff1a; 字符串在…

使用requests库进行网络爬虫:IP请求错误的解决方法

目录 引言 一、了解requests库 二、遇到的问题 三、解决方法 1、随机化IP地址 2、减少请求频率 3、使用User Agent模拟浏览器行为 4、使用Cookies 四、注意事项 五、使用代理池 六、总结 引言 在利用Python的requests库进行网络爬虫操作时&#xff0c;我们有时会遇…

jbase实现通用码表

没有通用码表的体系是不完美的&#xff0c;当年我用C#能实现的通用码表&#xff0c;现在在java一样的实现了&#xff0c;通用码表对提高开发效率和降低开发成本的作用巨大&#xff0c;开发可以专注写业务&#xff0c;而不必被太多的维护界面束缚。进而体现在产品竞争力上面&…

前端开发好用的vscode插件

1.TONGYI Lingma 通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研发智能问答、异常报错排查等能力&#xff0c;并针对阿里云 SDK/API 的使用场景调优&#xff0…

本地jar导入maven

一、通过dependency引入 1.1. jar包放置&#xff0c;建造lib目录 1.2. pom.xml文件 <dependency><groupId>zip4j</groupId><artifactId>zip4j</artifactId><version>1.3.2</version><!--system&#xff0c;类似provided&#x…

python趣味编程-5分钟实现一个打字速度测试(含源码、步骤讲解)

Python速度打字测试是用 Python 编程语言编写的,速度打字测试 Python项目理念,我们将构建一个令人兴奋的项目,通过它您可以 检查 甚至 提高 您的打字速度。 为了创建图形用户界面(GUI),我们将使用 用于处理图形的pygame库。 Python 打字速度测试有利于学生或初学者提高…

C#,数值计算——插值和外推,曲线插值(Curve_interp)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Object for interpolating a curve specified by n points in dim dimensions. /// </summary> public class Curve_interp { private int dim { get; s…

qt-C++笔记之treeWidget初次使用

qt-C笔记之treeWidget初次使用 code review! 文章目录 qt-C笔记之treeWidget初次使用1.运行2.文件结构3.main.cpp4.widget.h5.widget.cpp6.widget.ui7.main.qrc8.qt_widget_test.pro9.options.png 1.运行 2.文件结构 3.main.cpp 代码 #include "widget.h"#include…