C/C++ 内存管理
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); }
该段代码的在内存中的存储如图所示,static修饰的为静态变量,globalVal为全局变量,因此这两种都在数据段区域。malloc 、calloc、realloc开辟的动态空间一般都在堆上,指针,数据名称等都在栈中。
2 、C语言中动态内存管理方式:malloc、calloc、realloc、free
1.malloc、calloc、realloc三者的区别
- malloc函数用于动态分配指定大小的内存块,接收一个单位,即要分配的内存块大小,返回一个指向分配内存的void类型指针,但是如果开辟内存失败则会返回NULL。
- calloc函数和malloc一样都是用于动态分配的函数,但是与malloc不同的是,他有两个参数,其中第一个参数为要分配的元素数量,第二个参数为每个元素的大小,最后会将开辟好的内存初始化为零。开辟成功返回void类型指针,失败则返回NULL。
- realloc函数是用于重新分配先前分配的内存块大小,通常在动态内存分配时,用于扩容。该函数有两个参数,第一个参数为先前分配的内存块的指针,第二个参数为新内存块的大小,分配成功返回指向新内存块的指针,失败则返回NULL;在使用realloc扩容时,会分为就地扩容和异地扩容两种。就地扩容:在原始内存块的基础上进行扩容,如果原始内存块后边有足够的连续空间,就会在原始内存块后边进行扩容,这样避免了数据的搬迁,比较高效。异地扩容:异地扩容会在其他地方开辟一个新空间,然后将旧空间数据拷贝的新空间中,这样就会导致额外的内存拷贝操作。
2. malloc 函数的实现原理
内存池管理:
malloc()
函数会维护一个内存池,用于存储已分配和未分配的内存块。这个内存池可以是链表、树等数据结构,用于追踪哪些内存块是已分配的,哪些是可用的。内存块分配:当调用
malloc()
时,它会搜索内存池以找到足够大的未分配内存块。这通常涉及到内存块的大小和对齐要求。如果找到了合适的内存块,它将被标记为已分配,并返回其地址给调用者。内存块释放:当调用
free()
函数时,它将释放之前由malloc()
分配的内存块。释放内存块的过程通常涉及将其标记为未分配,并合并相邻的未分配块以避免内存碎片化。内存分配策略:
malloc()
实现还需要考虑内存分配的效率和内存使用的最优化。常见的内存分配策略包括首次适配(First Fit)、最佳适配(Best Fit)和最差适配(Worst Fit)等。这些策略的选择会影响到内存池的管理效率和内存使用的紧凑程度。内存对齐:在分配内存时,需要考虑内存对齐的问题。内存对齐是指内存分配时按照一定的字节边界进行分配,这样可以提高内存的访问效率。例如,有些平台要求某些数据类型必须在特定的内存地址上对齐,否则可能会导致性能问题或者错误。
错误处理:
malloc()
函数可能会失败,返回NULL
。这种情况可能是由于内存池已满或者系统资源不足导致的。因此,malloc()
的实现需要进行适当的错误处理,以确保程序的稳定性。
3、C++内存管理方式
在C++中,提出了他自己的内存管理方式:通过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[ ]要匹配使用。
4、operator new和operator delete函数
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的 全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过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来释放空间的
5、new和delete的实现原理
5.1 内置类型
如果申请的是内置类型的空间,new和malloc、delete和free基本类似,不同的地方是:delete、new释放和申请的是单个元素的空间,new[ ] 和delete[ ] 申请的是连续空间,而且new在申请空间失败时会抛异常, malloc会返回NULL。
5.2 自定义类型
new的原理
1. 调用operator new函数申请空间
2. 在申请的空间上执行构造函数,完成对象的构造
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的定义表达式进行显示调构造函数进行初始化。
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; }
7、常见问题
7.1 malloc/free和new/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。
系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统 资源的浪费,严重可导致系统效能减少,系统执行不稳定。
7.2.4如何避免内存泄漏
1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状 态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保 证。
2. 采用RAII思想或者智能指针来管理资源。
3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。 总结一下: 内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。
相关文章:
C/C++ 内存管理
1、C/C内存分布 首先我们来了解在一个程序中,代码主要存储在哪些地方; 1.栈:又叫堆栈,其中一般存储非静态局部变量、函数参数、返回值等,栈的增长是向下的。 2.内存映射段:是高效的 I/O 映射方式࿰…...
android pdf框架-10,相册浏览
MupdfViewer 这是最后apk,源码在前面的文章已经贴过了本站下载地址,只是不是最新的.可能不少是旧的内容. subsampling-scale-image-view这是一个大图片的分块加载的实现.比较不错的.滑动方面我觉得使用flinger的效果比它要流畅,惯性要好. 也有人把这个作成pdf渲染器.但翻页就…...
基于SSM的高校普法系统(有报告)。Javaee项目。ssm项目。
演示视频: 基于SSM的高校普法系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring Spri…...
数据结构刷题篇 之 【力扣二叉树基础OJ】详细讲解(含每道题链接及递归图解)
有没有一起拼用银行卡的,取钱的时候我用,存钱的时候你用 1、相同的树 难度等级:⭐ 直达链接:相同的树 2、单值二叉树 难度等级:⭐ 直达链接:单值二叉树 3、对称二叉树 难度等级:⭐⭐ 直达…...
Jackson 2.x 系列【6】注解大全篇二
有道无术,术尚可求,有术无道,止于术。 本系列Jackson 版本 2.17.0 源码地址:https://gitee.com/pearl-organization/study-jaskson-demo 文章目录 注解大全2.11 JsonValue2.12 JsonKey2.13 JsonAnySetter2.14 JsonAnyGetter2.15 …...
在低成本loT mcu上实现深度神经网络端到端自动部署-深度神经网络、物联网、边缘计算、DNN加速——文末完整资料
目录 前言 DNN 量化神经网络 并行超低功耗计算范式 面向内存的部署 结果 原文与源码下载链接 REFERENCES 前言 在物联网极端边缘的终端节点上部署深度神经网络( Deep Neural Networks,DNNs )是支持普适深度学习增强应用的关键手段。基于低成本MCU的终端节点…...
【linux】基础IO |文件操作符
需要掌握:操作文件,本质:进程操作文件。进程和文件的关系 向文件中写入,本质上向硬件中写入->用户没有权利直接写入->操作系统是硬件的管理者,我们可以通过操作系统往硬件写入->操作系统必须提供系统调用&…...
探索 2024 年 Web 开发最佳前端框架
前端框架通过简化和结构化的网站开发过程改变了 Web 开发人员设计和实现用户界面的方法。随着 Web 应用程序变得越来越复杂,交互和动画功能越来越多,这是开发前端框架的初衷之一。 在网络的早期,网页相当简单。它们主要以静态 HTML 为特色&a…...
解决: MAC ERROR [internal] load metadata for docker.io/library/openjdk:17
错误信息: ERROR [internal] load metadata for docker.io/library/openjdk:17 ERROR: failed to solve: openjdk:17: error getting credentials - err: exit status 1, out: 解决方法: running this command rm ~/.docker/config.json before …...
View事件分发
MotionEvent 1.简介 MotionEvent 是Android系统中一个非常重要的类,它代表了屏幕上发生的触摸事件。当用户在屏幕上触摸、滑动或者长按时,都会生成一个MotionEvent对象,这个对象包含了触摸动作的各种信息。 2.事件类型 ACTION_DOWN&#x…...
监听页面的使用时间
如果是比较新的vue架构(推荐,参考若依) 监听create()和destory()两个函数,写通用的js调用函数,在路由守卫的时候使用,就可以获取到每个页面停留时间 如果是比…...
【 yolo红外微小无人机-直升机-飞机-飞鸟目标检测】
yolo无人机-直升机-飞机-飞鸟目标检测 1. 小型旋翼无人机目标检测2. yolo红外微小无人机-直升机-飞机-飞鸟目标检测3. yolo细分类型飞机-鸟类-无人机检测4. yolo红外大尺度无人机检测5. 小型固定翼无人机检测6. 大型固定翼无人机检测7. yolo航空俯视场景下机场飞机检测 1. 小型…...
Redis与数据库的一致性
Redis与数据库的数据一致性 在使用Redis作为应用缓存来提高数据的读性能时,经常会遇到Redis与数据库的数据一致性问题。简单来说,就是同一份数据同时存在于Redis和数据库,如何在数据更新的时候,保证两边数据的一致性。首先&#…...
使用maxwell实时同步mysql数据到kafka
一、软件环境: 操作系统:CentOS release 6.5 (Final) java版本: jdk1.8 zookeeper版本: zookeeper-3.4.11 kafka 版本: kafka_2.11-1.1.0.tgz maxwell版本:maxwell-1.16.0.tar.gz 注意 : 关闭所有机器的防火墙,同时注意…...
知识图谱与大数据:区别、联系与应用
目录 前言1 知识图谱1.1 定义1.2 特点1.3 应用 2 大数据2.1 定义2.2 应用 3. 区别与联系3.1 区别3.2 联系 结语 前言 在当今信息爆炸的时代,数据成为了我们生活和工作中不可或缺的资源。知识图谱和大数据是两个关键概念,它们在人工智能、数据科学和信息…...
Nagios工具
一 nagios 相关概念 Nagios 是一款开源的免费网络监视工具,能有效监控 Windows、Linux 和 Unix 的主机状态,交换机路由器等网络设置,打印机等。在系统或服务状态异常时发出邮件或短信报警第 一时间通知网站运维人员,在状态恢复后…...
微信小程序全局数据共享
文章目录 安装MobX相关的包根目录创建store文件夹,添加store.js文件绑定到页面中绑定到组件 mobx-miniprogram和mobx-miniprogram-bindings实现全局数据共享 mobx-miniprogram用来创建Store实例对象 mobx-miniprogram-bindings用来把Store中的共享数据或方法&…...
算法训练营第24天|回溯算法理论基础 LeetCode 77.组合
终于把二叉树做完了!开始新的篇章,回溯! 回溯算法理论基础 回溯算法题目分类: 1.组合 2.分割 3.子集 4.排列 5.棋盘问题 什么是回溯? 回溯叫做回溯搜索法,是一种搜索方式。回溯是递归的副产品&…...
pip永久修改镜像地址
修改命令: pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/ 效果: 会在C:\Users\PC(用户名)\AppData\Roaming\pip目录下新增或修改文件pip.ini 文件内容: [global] index-url https://pypi.tuna.tsinghua.e…...
RK3588平台开发系列讲解(硬件篇-功能外设2)
USB2.0/USB3.0 电路 RK3588 芯片内置两个USB3.0 OTG控制器(内嵌2个USB2.0 OTG,下图绿色处),1个USB3.0 HOST 控制器,2个USB2.0 HOST控制器。 这些控制器与PHY的内部复用图如下: USB3.0 OTG0 控制器支持SS/H…...
SpringBoot学习记录
SpringBoot是用于加速Spring开发的。 我们先来看看如何使用SpringBoot来创建一个基于Web的程序,可以发现相较于SpringMVC其有巨大改变。 3.开发控制器类 GetMapping("/{id}")public String getById(PathVariable Integer id){System.out.println("…...
财富池指标--通达信顾比均线实战指标免费源码
顾比均线是由两组均线构成,短期组为3、5、8、10、12、15。长期组为:30、35、40、45、50、60。顾比均线由澳大利亚的投资家戴若-顾比先生发明,因此叫顾比线。 顾比均线可以广泛运用于股票、期货和外汇交易中,只要是能运用K线图的投…...
AJAX(一):初识AJAX、http协议、配置环境、发送AJAX请求、请求时的问题
一、什么是AJAX 1.AJAX 就是异步的JS和XML。通过AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。 2.XML 可扩展标记语言。XML被设计用来传输和…...
idea常用的快捷键总结:
idea常用的快捷键总结: Ctrl相关的: Ctrl F 在当前文件进行文本查找 (必备) Ctrl R 在当前文件进行文本替换 (必备) Ctrl Z 撤销 (必备) Ctrl Y 删除光标所在行 或 删除选中的…...
LeetCode 热题 100 题解(一):哈希部分
《LeetCode热题 100》 经过了两个多月,终于刷完了代码随想录的题目,现在准备开始挑战热题一百了,接下来我会将自己的题解以博客的形式同步发到力扣和 c 站,希望在接下来的征程中与大家共勉! 题组一:哈希 题…...
C语言 | qsort()函数使用
目录: 1.qsort介绍 2.使⽤qsort函数 排序 整型数据 3.使⽤qsort函数 排序 结构体数据 4. qsort函数的模拟实现冒泡排序 qsort()函数 是一个 C语言编译器函数库自带的排序函数, 它可以对指定数组(包括字符串,二维数组&#x…...
继承的特点 | java
/*Java中继承的特点:A:Java只支持单继承,不支持多继承。 B:Java支持多层继承(继承体系),间接继承 */class Father(){} class Mother(){}class son extends Father(){} // 正确 class son2 extends Father , Mother {} // 不正确 1. Java只支持单继承…...
6、jenkins项目构建类型-项目类型介绍
文章目录 一、自由风格项目1、拉取代码2、演示改动代码后的持续集成二、Maven项目构建三、Pipeline流水线项目构建(☆☆☆)1、Pipeline简介(1)概念(2)使用Pipeline有以下好处(3)如何创建Jenkins Pipeline呢?2、安装Pipeline插件3、Pipeline语法快速入门(1)Declarati…...
指针函数的应用——找出哪些学生有不及格的科目
下面的代码实现了以下功能: 定义了一个函数 getFailStudent,它接收一个指向整数数组的指针,并遍历该数组,查找是否存在不及格的成绩。如果找到了不及格的成绩,就返回指向不及格学生所在行的指针;否则返回 N…...
【微服务】Gateway
文章目录 1.基本介绍官方文档:https://springdoc.cn/spring-cloud-gateway/#gateway-starter1.引出网关2.使用网关服务架构图3.Gateway网络拓扑图(背下来)4.Gateway特性5.Gateway核心组件1.基本介绍2.断言3.过滤 6.Gateway工作机制 2.搭建Gat…...
wordpress域名访问不了/长春网站优化体验
前言什么情况下会触发类加载的进行呢?本文将结合代码demo谈谈几种情况,希望对大家有帮助。类加载时机什么情况需要开始类加载过程的第一阶段:加载?Java虚拟机规范中并没有进行强制约束,这点可以交给虚拟机的具体实现来…...
客厅装修风格/乐陵seo优化
小试牛刀 WiFi 远控 wendu 废话 少说 直接上代码 DH11三根线 信号线 接2 WiFi 模块 r-------t t--------r en&vcc------3.3v剩下的 共地的啦 double Fahrenheit(double celsius) { return 1.8 * celsius 32; } //摄氏温度度转化为华氏温度 double Kelvin(doubl…...
wordpress导航栏制作/济南优化网页
在《敏捷个人价值观,欢迎提出你的意见和你的价值观》中我介绍了一下我对敏捷个人价值观的一点初步理解,在这里也很感谢大家对blog的积极回复以及直接给我发邮件进行交流,你们的反馈是我们完善敏捷个人的最好参与方式。 大家对价值观的态度 上…...
wordpress怎么提速/百度秒收录排名软件
这么久没有写博客了,今天给大家分享一些多file文件的操作。一般可以用到清理垃圾获取文件大小 删除文件等操作,可以直接用于工具类里面,直接做操作便可以public final class FileUtils { public static long fileLen 0;public static void d…...
宝塔面板怎么做自己的网站/免费网页设计制作网站
再来看饮料厂在“原始时代”如何管理生产过程的吧。首先总经理须根据对需求的预测来安排生产计划,并根据物料和生产能力将此生产计划转为精确到时间、数量的详细的产品计划;在确定了生产计划之后,,就会把生产产品的数量转化为所需物料的数量&…...
响水做网站的价格/seo优化价格
对象的序列化主要解决的是对象状态的保存问题。这里所说的“对象状态”,其实就是指某一时刻对象所拥有的各个字段值的集合。 序列化最主要的作用有:1、在进程下次启动时读取上次保存的对象的信息 2、在不同的AppDomain或进程之间传递数据 3、在分布式应用…...