C++传送锚点的内存寻址:内存管理
文章目录
- 1.C/C++内存分布回顾
- 2.C++内存管理
- 2.1 内存申请
- 2.2 operator new与operator delete函数
- 2.3 定位new表达式
- 3.关于内存管理的常见知识点
- 3.1 malloc/free和new/delete的区别
- 3.2 内存泄漏
- 希望读者们多多三连支持
- 小编会继续更新
- 你们的鼓励就是我前进的动力!
继C语言初步学习了内存动态管理,本篇将继续学习C++部分更深入底层逻辑的内存管理
1.C/C++内存分布回顾

程序中需要存储的数据:局部数据、静态数据和全局数据、常量数据、动态申请数据
常量和可变常量的区别
经常很多人以为加了const的变量就是常量,但其实不是的,这叫
可变常量,例如const int* ptr,其实还是可以修改的,它可以指向不同的常量整数,但不能通过该指针修改所指向的值。
🔥检查类型存储位置的小tips:

看地址存放是否相近,相近则存放在同一区域,相差巨大则存放在不同区域
2.C++内存管理
我们直到在堆上动态开辟空间需要使用malloc,realloc等函数,不仅要保证前后类型一致,还要断言空指针,感觉还是太麻烦了,所以在C++使用了更简洁方便的动态开辟函数
2.1 内存申请
通过new和delete操作符进行动态内存管理
🚩动态申请1个int类型的空间
//C
int* p1 = (int*)malloc(sizeof(int));
free(p1);//C++
int* p2 = new int;
delete p2;
🚩动态申请存储10个int类型的数组
//C
int* p3 = (int*)malloc(sizeof(int) * 10);
free(p3);//C++
int* p4 = new int[10];
delete[] p4;
🚩动态申请存储1个int类型的空间并初始化为10
int* p5 = new int(10);
delete p5;
🚩动态申请数组并初始化多个元素
int* p6 = new int[10] {1,2,3};
delete[] p6;
🚩访问开辟的数组元素
int* p4 = new int[10];
cout << p4[0] << endl;
delete[] p4;
对于指针 p4,p4[i] 实际上等价于 *(p4 + i)。也就是说,p4[0] 表示访问 p4 所指向的内存位置(即数组的第一个元素)的值
那么new和delete存在的意义是什么?
在C语言中,malloc只完成了纯粹的开空间操作,虽然calloc也能对空间初始化,但是只能将所有元素初始化
在C++中,new能够初始化部分元素,比如在链表里能够调用构造函数来完成初始化操作,省去了写BuyNewnode函数的麻烦。delete相对于free会进行严格的类型检查,确保释放的是new开辟的空间,而且会调用析构函数
🔥值得注意的是:

申请和释放单个元素的空间,使用new和delete操作符;申请和释放连续的空间,使用new[]和delete[],注意要匹配起来使用
2.2 operator new与operator delete函数
我们知道malloc是开空间,new是通过开空间+构造函数实现的,那么new的开空间可以直接调用malloc吗,答案是不可以的
首先我们要知道面向对象开空间失败喜欢抛异常而不是返回nullptr
🚩malloc开无限大空间

malloc开空间没有显示任何错误难以发现
🚩new开无限大空间

new开空间会在开空间失败后抛出异常,用try...catch...捕获异常显示具体错误
/*
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 new的底层代码,new的开空间错误是要抛异常的,不能直接调用,而是new先调用operator new,然后operator new再调用malloc开空间。实际上malloc是被封装在了operator new里面的

对自定义类型进行操作时,调试状态下转到反汇编可以发现有两条call指令,一条调用operator new,一条调用构造函数,也能证实我们上面的说法,operator delete也是同理
那么又延伸出另一个问题,operator new和operator delete的调用顺序是怎么样的?
假设类Stack需要开辟动态数组_arry,容量_capacity,大小_size
Stack* p1 = new Stack;
delete p1;

p1作为指针变量存放地址,在栈上存储,然后new的空间在堆上开辟,_array又指向开辟的数组。如果按我们正常想的先调用operator delete释放堆空间,那么_array指向的数组即使调用析构函数也找不到,无法释放
因此我们可以整理出operator new和operator delete的调用顺序
- 调用operator new开辟空间
- 调用构造函数
- 调用析构函数
- 调用operator delete释放空间
2.3 定位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;
}
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象,这里p1,p2只是个自定义类型,无法调用构造函数,所以要用定位new
其语法形式为:
new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表
在实际应用中,定位new一般用于池化技术,也就是向内存申请一块内存池使用,因为频繁的向内存申请堆太麻烦了,所以申请一块内存池用于堆开辟空间
但是内存池的分配操作仅仅是对内存指针进行移动和管理,它只负责提供一块可用的原始内存,并没有内存初始化的操作
当使用 new 操作符来
创建对象时,它会完成两个主要步骤:首先分配内存,然后自动调用对象的构造函数对这块内存进行初始化。但内存池的分配操作只是完成了第一步,即提供内存,并没有触发构造函数调用的机制,此时定位new的作用就体现出来了,显式调用构造函数实现初始化操作
3.关于内存管理的常见知识点
3.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在释放空间前会调用析构函数完成空间中资源的清理
3.2 内存泄漏
什么是内存泄漏?
内存泄漏指因为疏忽或错误造成
程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费
如何检测内存泄漏?
在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.
因此写代码时一定要小心,尤其是动态内存操作时,一定要记着释放。但有些情况下总是防不胜防,简单的可以采用上述方式快速定位下。如果工程比较大,内存泄漏位置比较多,不太好查时一般都是借助第三方内存泄漏检测工具处理的
在linux下内存泄漏检测: linux下几款内存泄漏检测工具
在windows下使用第三方工具: VLD工具说明
其他工具: 内存泄漏工具比较
内存泄漏非常常见,解决方案分为两种:
事前预防型,如智能指针等事后查错型,如泄漏检测工具
希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力!

相关文章:
C++传送锚点的内存寻址:内存管理
文章目录 1.C/C内存分布回顾2.C内存管理2.1 内存申请2.2 operator new与operator delete函数2.3 定位new表达式 3.关于内存管理的常见知识点3.1 malloc/free和new/delete的区别3.2 内存泄漏 希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力! 继C语…...
两种交换排序算法--冒泡,快速
目录 1.冒泡排序原理 2.快速排序原理 3.冒泡代码实现 4.快速排序代码实现 1.冒泡排序原理 冒泡排序(Bubble Sort)是一种简单的排序算法,基本思想是通过反复交换相邻的元素,直到整个序列有序。它的名字来源于较大的元素像气泡…...
循序渐进kubernetes-RBAC(Role-Based Access Control)
文章目录 概要Kubernetes API了解 Kubernetes 中的 RBACRoles and Role Bindings:ClusterRoles and ClusterRoleBindings检查访问权限:外部用户结论 概要 Kubernetes 是容器化应用的强大引擎,但仅仅关注部署和扩展远远不够,集群的安全同样至…...
《从因果关系的角度学习失真不变表示以用于图像恢复》学习笔记
paper:2303.06859 GitHub:lixinustc/Causal-IR-DIL: Distortion invariant feature learning for image restoration from a causality perspective 2023 CVPR 目录 摘要 1、介绍 1.1 图像修复任务 1.2 失真不变表示学习 1.3 因果效应估计的挑战…...
亚博microros小车-原生ubuntu支持系列:16 机器人状态估计
本来想测试下gmapping建图,但是底层依赖了yahboomcar_bringup做底层的数据处理,所以先把依赖的工程导入。 程序启动后,会订阅imu和odom数据,过滤掉一部分的imu数据后,然后与odom数据进行融合,最后输出一个…...
Greenplum临时表未清除导致库龄过高处理
1.问题 Greenplum集群segment后台日志报错 2.回收库龄 master上执行 vacuumdb -F -d cxy vacuumdb -F -d template1 vacuumdb -F -d rptdb 3.回收完成后检查 仍然发现segment还是有库龄报警警告信息发出 4.检查 4.1 在master上检查库年龄 SELECT datname, datfrozen…...
【Unity3D】实现横版2D游戏角色二段跳、蹬墙跳、扶墙下滑
目录 一、二段跳、蹬墙跳 二、扶墙下滑 一、二段跳、蹬墙跳 GitHub - prime31/CharacterController2D 下载工程后直接打开demo场景:DemoScene(Unity 2019.4.0f1项目环境) Player物体上的CharacterController2D,Mask添加Wall层…...
mybatis(134/134)完结
一级缓存(默认情况下开启)同一个sqlsession中执行相同的查询语句走一级缓存 二级缓存 :同一个sqlsessionfactory,sqlsession关闭了才会将一级缓存提交到二级缓存中 外部编写的缓存 PageHelper插件:方便进行分页&#x…...
PaddleSeg 从配置文件和模型 URL 自动化运行预测任务
git clone https://github.com/PaddlePaddle/PaddleSeg.git# 在ipynb里面运行 cd PaddleSegimport sys sys.path.append(/home/aistudio/work/PaddleSeg)import os# 配置文件夹路径 folder_path "/home/aistudio/work/PaddleSeg/configs"# 遍历文件夹,寻…...
人工智能丨视觉识别在自动化测试中的应用
视觉识别:自动化测试的新纪元 在当今快速发展的科技时代,软件测试正面对着日益复杂的挑战。作为其中一个关键领域,自动化测试不断寻求创新的方法,以提高测试效率和准确性。在这一背景下,视觉识别技术的引入为自动化测…...
lambda 表达式:Python中的极简艺术
lambda 表达式:Python中的极简艺术 — 让你的代码更简洁、更高效! 引言 在 Python 中,lambda 表达式是一种简洁的定义匿名函数的方式。它通常用于需要函数对象的场景,但又不需要显式定义一个完整函数的场合。本文将详细介绍 la…...
BLE透传方案,IoT短距无线通信的“中坚力量”
在物联网(IoT)短距无线通信生态系统中,低功耗蓝牙(BLE)数据透传是一种无需任何网络或基础设施即可完成双向通信的技术。其主要通过简单操作串口的方式进行无线数据传输,最高能满足2Mbps的数据传输速率&…...
无用知识研究:对std::common_type以及问号表达式类型的理解
先说结论:如果问号表达式能编译通过,那么std::common_type就能通过。因为common_type的底层依赖的就是?: common_type的实现里,利用了问号表达式:ternary conditional operator (?:) https://stackoverflow.com/questions/1432…...
苍穹外卖—订单模块
该模块分为地址表的增删改查、用户下单、订单支付三个部分。 第一部分地址表的增删改查无非就是对于单表的增删改查,较基础,因此直接导入代码。 地址表 一个用户可以有多个地址,同时有一个地址为默认地址。用户还可为地址添加例如&q…...
「 机器人 」扑翼飞行器的数据驱动建模核心方法
前言 数据驱动建模可充分利用扑翼飞行器的已有运行数据,改进动力学模型与控制策略,并对未建模动态做出更精确的预测。在复杂的非线性飞行环境中,该方法能有效弥补传统解析建模的不足,具有较高的研究与应用价值。以下针对主要研究方向和实现步骤进行整理与阐述。 1. 数据驱动…...
openeuler 22.03 lts sp4 使用 cri-o 和 静态 pod 的方式部署 k8s-v1.32.0 高可用集群
前情提要 整篇文章会非常的长…可以选择性阅读,另外,这篇文章是自己学习使用的,用于生产,还请三思和斟酌 静态 pod 的部署方式和二进制部署的方式是差不多的,区别在于 master 组件的管理方式是 kubectl 还是 systemctl有 kubeadm 工具,为什么还要用静态 pod 的方式部署?…...
Helm Chart 实战指南
Helm 是 Kubernetes 的包管理工具,而 Helm Chart 是 Helm 的核心概念,用于定义、安装和升级 Kubernetes 应用。本文将带你从零开始,通过实战演练,掌握 Helm Chart 的创建、配置和部署,帮助你高效管理 Kubernetes 应用。 1. 环境准备 在开始之前,确保你已经具备以下环境:…...
【数据结构】_顺序表经典算法OJ(力扣版)
目录 1. 移除元素 1.1 题目描述及链接 1.2 解题思路 1.3 程序 2. 合并两个有序数组 1.1 原题链接及题目描述 1.2 解题思路 1.3 程序 1. 移除元素 1.1 题目描述及链接 原题链接:27. 移除元素 - 力扣(LeetCode) 题目描述:…...
目前市场主流的AI PC对于大模型本地部署的支持情况分析-Deepseek
以下是目前市场主流AI PC对**大模型本地部署支持情况**的综合分析,结合硬件能力、软件生态及厂商动态进行总结: --- ### **一、硬件配置与算力支持** 1. **核心处理器架构** - **异构计算方案(CPUGPUNPU)**:主流…...
Vue3 v-bind 和 v-model 对比
1. 基本概念 1.1 v-bind 单向数据绑定从父组件向子组件传递数据简写形式为 : 1.2 v-model 双向数据绑定父子组件数据同步本质是 v-bind 和 v-on 的语法糖 2. 基础用法对比 2.1 表单元素绑定 <!-- v-bind 示例 --> <template><input :value"text&quo…...
MySQL分表自动化创建的实现方案(存储过程、事件调度器)
《MySQL 新年度自动分表创建项目方案》 一、项目目的 在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低。分表是一种有效的优化策略,它将数据分散存储在多…...
接口技术-第6次作业
目录 作业内容 解答 1.假设在一个系统中,8255A的端口地址为184H-187H,A口工作于方式1输出,B口工作于方式1输入,禁止中断,C口剩余的两根线PC5,PC4位输入,如下图所示,试编写初始化…...
计算机网络之计算机网络体系结构
一、定义与概述 计算机网络体系结构是计算机网络及其部件所应该完成功能的精确定义,这些功能由何种硬件或软件完成是遵循这种体系结构的。体系结构是抽象的,实现是具体的,是运行在计算机软件和硬件之上的。 二、主流模型 目前,…...
(1)Linux高级命令简介
Linux高级命令简介 在安装好linux环境以后第一件事情就是去学习一些linux的基本指令,我在这里用的是CentOS7作演示。 首先在VirtualBox上装好Linux以后,启动我们的linux,输入账号密码以后学习第一个指令 简介 Linux高级命令简介ip addrtou…...
网络直播时代的营销新策略:基于受众分析与开源AI智能名片2+1链动模式S2B2C商城小程序源码的探索
摘要:随着互联网技术的飞速发展,网络直播作为一种新兴的、极具影响力的媒体形式,正逐渐改变着人们的娱乐方式、消费习惯乃至社交模式。据中国互联网络信息中心数据显示,网络直播用户规模已达到3.25亿,占网民总数的45.8…...
CSS(快速入门)
欢迎大家来到我的博客~欢迎大家对我的博客提出指导,有错误的地方会改进的哦~点击这里了解更多内容 目录 一、什么是CSS?二、基本语法规范三、CSS选择器3.1 标签选择器3.2 id选择器3.3 class选择器3.4 通配符选择器3.5 复合选择器 四、常用CSS样式4.1 color4.2 font…...
waitpid使用
waitpid 是 Unix/Linux 系统中用于等待子进程状态变化的系统调用。它允许父进程挂起执行,直到指定的子进程终止或者发生了其他指定的状态变化。 waitpid 的语法 pid_t waitpid(pid_t pid, int *status, int options); pid: 要等待的子进程的进程 ID,特殊…...
对顾客行为的数据分析:融入2+1链动模式、AI智能名片与S2B2C商城小程序的新视角
摘要:随着互联网技术的飞速发展,企业与顾客之间的交互方式变得日益多样化,移动设备、社交媒体、门店、电子商务网站等交互点应运而生。这些交互点不仅为顾客提供了便捷的服务体验,同时也为企业积累了大量的顾客行为数据。本文旨在…...
MySQL查询优化(三):深度解读 MySQL客户端和服务端协议
如果需要从 MySQL 服务端获得很高的性能,最佳的方式就是花时间研究 MySQL 优化和执行查询的机制。一旦理解了这些,大部分的查询优化是有据可循的,从而使得整个查询优化的过程更有逻辑性。下图展示了 MySQL 执行查询的过程: 客户端…...
pytorch线性回归模型预测房价例子
import torch import torch.nn as nn import torch.optim as optim import numpy as np# 1. 创建线性回归模型类 class LinearRegressionModel(nn.Module):def __init__(self):super(LinearRegressionModel, self).__init__()self.linear nn.Linear(1, 1) # 1个输入特征&…...
