【C++初阶】6. CC++内存管理
1. 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);
}
//1. 选择题:
//选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
//globalVar在哪里?____ staticGlobalVar在哪里?____
//staticVar在哪里?____ localVar在哪里?____
//num1 在哪里?____
//
//char2在哪里?____ * char2在哪里?___
//pChar3在哪里?____ * pChar3在哪里?____
//ptr1在哪里?____ * ptr1在哪里?____
//2. 填空题:
//sizeof(num1) = ____;
//sizeof(char2) = ____; strlen(char2) = ____;
//sizeof(pChar3) = ____; strlen(pChar3) = ____;
//sizeof(ptr1) = ____;
【说明】
- 栈又叫堆栈–非静态局部变量/函数参数/返回值等等,栈是向下增长的。
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
(属于Linux相关模块,会在Linux博客中详细描述,现在仅需了解即可)- 堆用于程序运行时动态内存分配,堆是可以上增长的。
- 数据段–存储全局数据和静态数据。
- 代码段–可执行的代码/只读常量
2. C语言中动态内存管理方式:malloc/calloc/realloc/free
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);
}
这里的p2并不需要释放,因为若是空间不够realloc p3 会先释放p2原来的空间,再重新找一块空间
若是空间够,p3 和 p2 指向同一块空间
3. C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
3.1 new/delete操作内置类型
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[]
注意:匹配起来使用。
3.2 new和delete操作自定义类型
注意:在申请自定义类型的空间时,new会自动调用构造函数,delete自动会调用析构函数,而malloc与free不会。
关键点:
new和delete、malloc和free、new[ ] 和delete[ ] 必须要匹配使用
总结:
new / delete 相较于 malloc / free的优势在于:
1.new / delete会自动调用构造 / 析构函数,而malloc / free不会
2. new 不需要检查返回值来判断是否开辟成功,而malloc需要
4. operator new与operator delete函数(重点)
4.1 operator new与operator delete函数
底层new的实现:
- operator new ==》本质也就是经过封装的malloc
- 调用构造函数
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
//以下为库中的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)
C语言中的free是_free_dbg的宏定义,而C++中delete中也有_free_dbg
为啥要封装malloc,申请内存失败要报异常呢?因为这样才符合C++面向对象处理错误的方式
5. new和delete的实现原理
5.1 内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本类似
不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
5.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来释放空间
对于operator new [ ] / operator delete [ ] 而言,最终调用的也是operator new / 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/free和new/delete的区别(重点)
不能采用死记硬背的方式,要结合实例深刻理解
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。 不同的地方是:
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可
- malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需 要捕获异常
- 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
7.2 内存泄漏
7.2.1 什么是内存泄漏,内存泄漏的危害?
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
7.2.2 内存泄漏是内存丢了,还是指针丢了?
内存泄漏是指指针丢了该空间已经不需要再使用了(需要释放),但是找不到访问该空间的方法【形象的比喻:站着茅坑不拉屎】
而不是说内存丢了,操作系统的内存空间并未减少
7.2.3 如何避免内存泄漏?
- 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
- 采用RAII思想或者智能指针来管理资源。
- 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
- 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。
总结一下:
内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。
相关文章:

【C++初阶】6. CC++内存管理
1. 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* …...

【数据结构】万字超详解顺序表(比细狗还细)
我这个人走得很慢,但是我从不后退。 ——亚伯拉罕林肯 目录 一.什么是线性表? 二.什么是顺序表? 三.接口函数的实现 1.创建工程 2.构造顺序表 3.初始化顺序表 3.初始化顺序表 4.顺序表的尾插 5.顺序…...
yolov5 剪枝、蒸馏、压缩、量化
文章大纲 剪枝推理优化YOLOv5 剪枝可能出现的问题参考文献与学习路径考察神经网络时期重要的激活函数sigmoid和tanh,它们有一个特点,即输入值较大或者较小的时候,其导数变得很小,而在训练阶段(详见1.2.3节),需要求取多个导数值,并将每层得到的导数值相乘,这样一旦层数…...

如何用python代码,更改照片尺寸,以及更换照片底色
前言 python浅浅替代ps?如何用代码来p证件照并且更换底色? 唉,有个小姐姐给我扔了张照片,叫我帮忙给她搞成证件照的尺寸还得换底色,她说自己忙的很 可惜电脑上没有ps只有pycharm,没得办法只能来试试看代…...

【pygame游戏】Python实现蔡徐坤大战篮球游戏【附源码】
前言 话说在前面,我不是小黑子~😏 本文章纯属技术交流~娱乐 前几天我获得了一个坤坤打篮球的游戏,也给大家分享一下吧~ 好吧,其实并不是这样的游戏,往下慢慢看吧。 准备工作 开发环境 Python版本:3.7.8 …...

通过指针引用字符串详解,以及字符指针变量和字符数组的比较
在平常的案例中已大量地使用了字符串,如在 printf函数中输出一个字符串。这些字符串都是以直接形式 (字面形式) 给出的,在一对双引号中包含若干个合法的字符。在本节中将介绍使用字符串的更加灵活方便的方法:通过指针引用字符串。 目录 一、…...
Vue基本整合(一)
NPM安装npm是node的包管理工具https://nodejs.org/en/脚手架安装npm i -g vue/clihttps://registry.npmjs.org/vue浏览器插件https://devtools.vuejs.org/guide/installation.html#chromehttps://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhble…...
C++编程之 万能引用
万能引用是一种可以同时接受左值或右值的引用,它的形式是T&&,其中T是一个模板参数。万能引用不是C的一个新特性,而是利用了模板类型推导和引用折叠的规则来实现的功能。 模板类型推导 模板类型推导是指在调用一个模板函数时&#x…...

【JavaScript速成之路】JavaScript内置对象--数组对象
📃个人主页:「小杨」的csdn博客 🔥系列专栏:【JavaScript速成之路】 🐳希望大家多多支持🥰一起进步呀! 文章目录前言数组对象1,数组类型检测2,数组元素增删3,…...

【华为机试真题详解 Python实现】最差产品奖【2023 Q1 | 100分】
文章目录 前言题目描述输入描述输出描述示例 1题目解析参考代码前言 《华为机试真题详解》专栏含牛客网华为专栏、华为面经试题、华为OD机试真题。 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议! 本文解法非最优解(即非性能…...
[算法] 二分查找
package com.guigu.search;import java.util.ArrayList; import java.util.Arrays;/*** author: guorui fu* versiion: 1.0* 二分查找 直接适用于已经排序完成的数组*/ public class BinarySearch {public static void main(String[] args) {int arr[] {1,8,8,89,101,1234};Ar…...
HTML面经
1.src与href的区别 src用于替换当前元素,如script标签,img标签等。当html解析到这些标签时,会暂停解析,将指定的资源下载下来,嵌入到所在位置内。href的话则是一个当前页面与引用资源之间的链接,如link标签…...
我的十年编程路 2021年篇
慢慢地,时光走过了8个年头,来到2021年。 站在2021年,回望8年的过往,没有大的起伏和波澜。或许是上天的眷顾,我的事业发展一直都很顺利。当然,弯路也走过一些,而且工作其实挺辗转的,…...

ElasticSearch 8 学习笔记总结(七)
感觉这些东西没必要认真学,了解一下,工作用到再学。 文章目录一、ES8 EQL 介绍二、ES8 EQL基本操作 与 安全检测三、ES SQL操作四、ES SQL与DSL的关系五、ES 常用的SQL操作六、ES datagrip配置ES七、ES8 自然语言处理 NLP八、ES8 性能优化 之 缓存九、ES…...

【云原生】Docker 网络模式详解、容器间网络通信
当项目大规模使用 Docker 时,容器通信的问题也就产生了。要解决容器通信问题,必须先了解很多关于网络的知识。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,也有着很多不完善的地方,网络方面就是 Docker…...

Java开发 - 布隆过滤器初体验
目录 前言 布隆过滤器 什么是布隆过滤器 布隆过滤器的作用 布隆过滤器原理 怎么设计布隆过滤器 布隆过滤器使用案例 安装布隆过滤器 添加依赖 添加配置 添加工具类 添加测试代码 简单测试 特别提醒 结语 前言 前面三篇,已经把消息队列…...
【计算机组成原理 - 第一章】计算机系统概论(完结)
本章参考王道考研相关课程: 【2021版】1.2.1_计算机硬件的基本组成_哔哩哔哩_bilibili 【2021版】1.2.2_认识各个硬件部件_哔哩哔哩_bilibili 【2021版】1.2.3_计算机系统的层次结构_哔哩哔哩_bilibili 【2021版】1.3_计算机的性能指标_哔哩哔哩_bilibili 目录 一、…...

C++类与对象(下)【详析】
类与对象(下) 目录类与对象(下)一、再谈构造函数1.构造函数体赋值2.初始化列表定义:注意点:总结:3.explicit关键字引入:explicit:二、 static成员回顾:static…...

exe反编译为.py文件
介绍公司以前的一个exe包,我们需要查看里面python源码,但是以前的py源码文件找不到,所以只能反编译,介绍一下反编译的过程。首先准备:pyinstxtractor.py这个文件,网上很多,自己下载准备查看二进…...

38 openEuler搭建FTP服务器-FTP总体介绍
文章目录38 openEuler搭建FTP服务器-FTP总体介绍38.1 FTP简介38.2 FTP使用到的端口38.3 vsftpd简介38 openEuler搭建FTP服务器-FTP总体介绍 38.1 FTP简介 FTP(File Transfer Protocol)即文件传输协议,是互联网最早的传输协议之一࿰…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...