目录

  • 【C++小白逆袭】内存管理从崩溃到精通的秘籍
    • 前言:为什么内存管理让我掉了N根头发?
    • 内存四区大揭秘:你的变量都住在哪里?🏠
      • 内存就像大学宿舍区 🏘️
    • C语言的内存管理:手动搬砖时代 🧱
      • 举个栗子 🌰
    • C++的内存管理:智能建房时代 🏗️
      • 内置类型:简单装修 🔨
      • 自定义类型:豪华装修 🏰
    • new和delete的底层魔法 🧙‍♂️
      • 简单说就是:
    • 内存管理避坑指南 🚫💣
      • 1. 匹配使用!匹配使用!匹配使用!
      • 2. 别做"渣男"!申请了就要释放
      • 3. 野指针是"幽灵",小心被附身
    • malloc/free vs new/delete:终极对决 🆚
    • 开篇答案揭晓 🎉
    • 总结:内存管理三板斧 🪓
      • 定位new:在已有的空间上"盖房子" 🏗️
    • operator new/delete的底层真相 🕵️‍♂️
    • 内存管理常见面试题 🤔
      • 1. malloc/calloc/realloc的区别?
      • 2. new和malloc的根本区别?
      • 3. 内存泄漏有哪些危害?
    • 最后的叮嘱 💌
      • 💻 定位new代码运行效果演示
    • 最后的最后... 🎁

在这里插入图片描述
🌟个人主页 :L_autinue_Star

🌟当前专栏:c++进阶


【C++小白逆袭】内存管理从崩溃到精通的秘籍

前言:为什么内存管理让我掉了N根头发?

刚学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); // 动态内存
}

灵魂拷问:这些变量都住在哪里?(答案在文末揭秘)

内存就像大学宿舍区 🏘️

其实内存分布就像我们的校园:

  • 代码段:相当于教学楼,存放可执行代码和常量(只读不修改)
  • 数据段:类似教师公寓,住着全局变量和静态变量(程序运行期间一直存在)
  • 栈区:好比临时自习室,局部变量/函数参数在这里(自动分配释放)
  • 堆区:就像校外出租房,需要自己找房(申请)和退租(释放)

在这里插入图片描述

💡 学霸笔记:栈是向下增长的(地址越来越小),堆是向上增长的(地址越来越大),就像两个方向相反的电梯!

C语言的内存管理:手动搬砖时代 🧱

C语言用四个函数管理内存,我称之为"内存F4":

  • malloc:申请空间(只给钱不装修)
  • calloc:申请空间并初始化为0(给钱+简单装修)
  • realloc:调整空间大小(换更大/小的房子)
  • free:释放空间(退租)

举个栗子 🌰

void Test() {// malloc: 申请4个int大小空间(16字节)int* p1 = (int*)malloc(sizeof(int)*4);// calloc: 申请4个int并初始化为0(比malloc多一步清零)int* p2 = (int*)calloc(4, sizeof(int));// realloc: 把p2的空间扩大到10个int(可能搬家哦!)int* p3 = (int*)realloc(p2, sizeof(int)*10);// 注意:realloc成功后p2可能失效,直接用p3就好啦!free(p3); // 一定要释放!不然房子就一直占着~
}

⚠️ 踩坑警告:realloc如果扩容失败会返回NULL,直接赋值可能丢失原指针!正确姿势是先用临时变量接收~

C++的内存管理:智能建房时代 🏗️

C++觉得C语言太麻烦,于是发明了newdelete这对"智能管家",不仅帮你找房,还负责装修(调用构造函数)和打扫(调用析构函数)!

内置类型:简单装修 🔨

void Test() {// 申请单个int(毛坯房)int* ptr4 = new int;// 申请int并初始化为10(简装房)int* ptr5 = new int(10);// 申请3个int数组(联排别墅)int* ptr6 = new int[3];// 记得匹配释放哦!delete ptr4;       // 拆单个房子delete ptr5;       // 拆简装房delete[] ptr6;     // 拆联排别墅([]不能忘!)
}

在这里插入图片描述

自定义类型:豪华装修 🏰

对于我们自己定义的类,newdelete会自动调用构造和析构函数,这可是C语言做不到的!

class A {
public:A(int a=0) : _a(a) { cout << "A():我出生啦!" << this << endl; }~A() { cout << "~A():我走啦!" << this << endl; }
private:int _a;
};int main() {A* p1 = (A*)malloc(sizeof(A)); // C语言方式:只建房子不装修A* p2 = new A(1);              // C++方式:建房子+装修(调用构造)free(p1);  // C语言方式:只拆房子不打扫delete p2; // C++方式:打扫卫生+拆房子(调用析构)return 0;
}

神奇时刻:运行这段代码,你会看到new创建的对象会打招呼,delete时会说再见,而malloc/free的对象啥也不说!

new和delete的底层魔法 🧙‍♂️

你以为new是直接变出空间的?其实它背后有两个"帮手":

  • operator new:负责申请空间(底层还是用malloc)
  • operator delete:负责释放空间(底层还是用free)

简单说就是:

new = operator new(申请空间) + 构造函数(初始化)
delete = 析构函数(清理) + operator delete(释放空间)

当申请失败时,malloc返回NULL,而new会抛出异常,所以C++不需要像C语言那样判空,而是用try-catch捕获异常~

内存管理避坑指南 🚫💣

1. 匹配使用!匹配使用!匹配使用!

重要的事情说三遍:

  • mallocfree
  • newdelete
  • new[]delete[](数组一定要加[]!)

2. 别做"渣男"!申请了就要释放

内存泄漏就像借了东西不还,次数多了系统就被"掏空"!😭

// 反面教材(千万别学!)
void badCode() {int* p = new int[100];// 忘记delete p; → 内存泄漏!
}

3. 野指针是"幽灵",小心被附身

释放后记得把指针置为NULL,不然就变成指向"坟场"的野指针:

int* p = new int;
delete p;
p = NULL; // 重要!避免野指针

malloc/free vs new/delete:终极对决 🆚

特性malloc/freenew/delete
身份函数操作符
初始化不初始化可初始化
返回值void*(需强转)直接返回对应类型
错误处理返回NULL抛异常
自定义类型只开空间开空间+构造/析构

开篇答案揭晓 🎉

还记得开头的变量都住在哪里吗?答案来啦:

  • globalVar → 数据段
  • staticGlobalVar → 数据段
  • staticVar → 数据段
  • localVar → 栈区
  • num1 → 栈区
  • char2 → 栈区(数组本身)
  • *char2 → 栈区(数组内容)
  • pChar3 → 栈区(指针本身)
  • *pChar3 → 代码段(字符串常量)
  • ptr1 → 栈区(指针本身)
  • *ptr1 → 堆区(指向的内容)

总结:内存管理三板斧 🪓

  1. 懂分区:知道变量住哪个"宿舍"
  2. 会申请:malloc/free是C爷爷,new/delete是C++管家
  3. 记得还:用完内存一定要释放,做个有始有终的好孩子!

希望这篇文章能帮你搞定内存管理!如果有收获,别忘了点赞收藏~ 有问题欢迎评论区交流,一起在C++的世界里打怪升级!🚀## 进阶内容:内存池与定位new 🏊‍♂️

当你需要频繁创建和销毁对象时(比如游戏中的子弹),频繁使用new/delete会导致内存碎片。这时候内存池就派上用场了——提前申请一大块内存,然后用定位new在上面创建对象,就像在游泳池里分配泳道一样高效!

定位new:在已有的空间上"盖房子" 🏗️

class A {
public:A(int a=0) : _a(a) { cout << "A():我出生在指定地址!" << this << endl; }
private:int _a;
};int main() {// 1. 先申请一块与A对象大小相同的"空地"A* p = (A*)malloc(sizeof(A));// 2. 用定位new在这块空地上"盖房子"(调用构造函数)new(p)A(10); // 注意语法:new(地址)类型(参数)// 3. 手动调用析构函数(因为delete不会自动调用)p->~A();// 4. 释放原始内存free(p);return 0;
}

🧠 学霸思考:定位new就像二手房装修——房子(内存)是现成的,但需要重新装修(调用构造函数)才能入住!

operator new/delete的底层真相 🕵️‍♂️

你可能好奇:new到底怎么申请内存的?其实它偷偷调用了operator new函数,相当于"装修公司"外包给"建筑队":

// operator new的简化实现
void* operator new(size_t size) {void* p = malloc(size); // 实际还是用malloc申请空间if (p == NULL) {throw bad_alloc(); // 申请失败抛异常(区别于malloc返回NULL)}return p;
}// operator delete的简化实现
void operator delete(void* p) {free(p); // 底层调用free释放空间
}

所以new和delete的工作流程是:

  1. new → operator new(申请空间) → 构造函数(初始化)
  2. delete → 析构函数(清理) → operator delete(释放空间)

内存管理常见面试题 🤔

1. malloc/calloc/realloc的区别?

  • malloc:只申请空间,不初始化
  • calloc:申请空间并初始化为0(适合数组)
  • realloc:调整已申请的空间大小(可能搬家)

2. new和malloc的根本区别?

最核心的区别是对自定义类型的处理:new会调用构造函数,delete会调用析构函数,而malloc/free不会!

3. 内存泄漏有哪些危害?

短期程序(如命令行工具)可能看不出影响,但长期运行的程序(如服务器)会越来越慢,最终崩溃!就像房间垃圾不清理,越堆越多直到无法住人~

最后的叮嘱 💌

内存管理就像理财——合理分配资源(内存),及时回收(释放),才能避免"破产"(程序崩溃)。刚开始可能会犯错,但多写多练,你也能成为内存管理大师!

如果这篇文章帮你理清了内存管理的思路,记得点赞收藏哦~ 有任何问题,欢迎在评论区留言,我们一起进步!🎉### 📝 内存管理自查清单(避坑必备)

常见错误解决方法严重程度
malloc后未判空if(p == NULL) { 处理错误 }⭐⭐⭐
new[] 搭配 delete(漏写[])严格使用 delete[] 释放数组⭐⭐⭐⭐
重复释放同一块内存释放后指针置为 NULL⭐⭐⭐
内存泄漏使用智能指针(后续文章讲解)⭐⭐⭐⭐⭐
野指针指针初始化/释放后置为 NULL⭐⭐⭐⭐

💻 定位new代码运行效果演示

如果运行定位new的示例代码,你会看到这样的输出:

A():我出生在指定地址!0x7f8a9b4052a0
~A():我走啦!0x7f8a9b4052a0

这证明定位new确实调用了构造函数,而手动调用p->~A()触发了析构函数~


最后的最后… 🎁

内存管理是C++的核心难点,也是面试官的"心头好"。刚开始写崩程序很正常,我曾经因为内存泄漏调试到凌晨三点(说多了都是泪😭)。但只要记住"申请了就释放,匹配使用工具"的原则,你一定能攻克这个难关!

如果这篇文章对你有帮助,别忘了点赞+收藏,也欢迎分享给正在学C++的小伙伴~ 关注我,后续还会更新智能指针、内存池等进阶内容哦!🚀

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

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

相关文章

【网络安全】利用 Cookie Sandwich 窃取 HttpOnly Cookie

未经许可,不得转载。 文章目录 引言Cookie 三明治原理解析Apache Tomcat 行为Python 框架行为窃取 HttpOnly 的 PHPSESSID Cookie第一步:识别 XSS 漏洞第二步:发现反射型 Cookie 参数第三步:通过 Cookie 降级实现信息泄露第四步:整合攻击流程修复建议引言 本文将介绍一种…

【工具】什么软件识别重复数字?

网上的数字统计工具虽多&#xff0c;但处理重复数字时总有点不尽如人意。 要么只能按指定格式输入&#xff0c;要么重时得手动一点点筛&#xff0c;遇上数据量多的情况&#xff0c;光是找出重复的数字就得另外花不少功夫。​ 于是我做了个重复数字统计器&#xff0c;不管是零…

CSS分层渲染与微前端2.0:解锁前端性能优化的新维度

CSS分层渲染与微前端2.0&#xff1a;解锁前端性能优化的新维度 当你的页面加载时间超过3秒&#xff0c;用户的跳出率可能飙升40%以上。这并非危言耸听&#xff0c;而是残酷的现实。在当前前端应用日益复杂、功能日益臃肿的“新常态”下&#xff0c;性能优化早已不是锦上添花的“…

AI Agent开发学习系列 - langchain之Chains的使用(5):Transformation

Transformation&#xff08;转换链&#xff09;是 LangChain 中用于“自定义数据处理”的链式工具&#xff0c;允许你在链路中插入任意 Python 代码&#xff0c;对输入或中间结果进行灵活处理。常用于&#xff1a; 对输入/输出做格式化、过滤、摘要、拆分等自定义操作作为 LLMC…

Druid 连接池使用详解

Druid 连接池使用详解 一、Druid 核心优势与架构 1. Druid 核心特性 特性说明价值监控统计内置 SQL 监控/防火墙实时查看 SQL 执行情况防 SQL 注入WallFilter 防御机制提升系统安全性加密支持数据库密码加密存储符合安全审计要求扩展性强Filter 链式架构自定义功能扩展高性能…

9.2 埃尔米特矩阵和酉矩阵

一、复向量的长度 本节的主要内容可概括为&#xff1a;当对一个复向量 z\pmb zz 或复矩阵 A\pmb AA 转置后&#xff0c;还要取复共轭。 不能在 zTz^TzT 或 ATA^TAT 时就停下来&#xff0c;还要对所有的虚部取相反的符号。对于一个分量为 zjajibjz_ja_jib_jzj​aj​ibj​ 的列向…

AI驱动的低代码革命:解构与重塑开发范式

引言&#xff1a;低代码平台的范式转移 当AI技术与低代码平台深度融合&#xff0c;软件开发正经历从"可视化编程"到"意图驱动开发"的根本性转变。这种变革不仅提升了开发效率&#xff0c;更重新定义了人与系统的交互方式。本文将从AI介入的解构层次、交互范…

zookeeper etcd区别

ZooKeeper与etcd的核心区别体现在设计理念、数据模型、一致性协议及适用场景等方面。‌ZooKeeper基于ZAB协议实现分布式协调&#xff0c;采用树形数据结构和临时节点特性&#xff0c;适合传统分布式系统&#xff1b;而etcd基于Raft协议&#xff0c;以高性能键值对存储为核心&am…

模拟注意力:少量参数放大 Attention 表征能力

论文标题 SAS: Simulated Attention Score 论文地址 https://arxiv.org/pdf/2507.07694 代码 见论文附录 作者背景 摩根士丹利&#xff0c;斯坦福大学&#xff0c;微软研究院&#xff0c;新加坡国立大学&#xff0c;得克萨斯大学奥斯汀分校&#xff0c;香港大学 动机 …

零基础|宝塔面板|frp内网穿透|esp32cam远程访问|微信小程序

1.准备好阿里云服务器和宝塔面板2.安装frp服务端3.测试(密码账号在详情里面)4.配置客户端#一、没有域名情况下 [common] server_addr #公网ip地址&#xff0c;vps server_port 7000 服务的bind_port token 12121212 [httpname] type tcp # 没有域名情况下使用 tcp local_i…

Spring Boot整合MyBatis+MySQL+Redis单表CRUD教程

Spring Boot整合MyBatisMySQLRedis单表CRUD教程 环境准备 1. Redis安装&#xff08;Windows&#xff09; # 下载Redis for Windows # 访问: https://github.com/tporadowski/redis/releases # 下载Redis-x64-5.0.14.1.msi并安装# 启动Redis服务 redis-server# 测试连接 redis-c…

linux学习第30天(线程同步和锁)

线程同步协同步调&#xff0c;对公共区域数据按序访问。防止数据混乱&#xff0c;产生与时间有关的错误。数据混乱的原因资源共享(独享资源则不会)调度随机(意味着数据访问会出现竞争)线程间缺乏必要同步机制锁的使用建议锁&#xff01;对公共数据进行保护。所有线程【应该】在…

JavaScript中的系统对话框:alert、confirm、prompt

JavaScript中的系统对话框&#xff1a;alert、confirm、prompt 在Web开发的世界里&#xff0c;JavaScript始终扮演着“桥梁”的角色——它连接用户与网页&#xff0c;让静态的页面焕发活力。而在这座桥梁上&#xff0c;系统对话框&#xff08;System Dialogs&#xff09;是最基…

圆幂定理深度探究——奥数专题讲义

圆幂定理深度探究——奥数专题讲义 开篇语&#xff1a;几何中的"隐藏等式" 在平面几何的星空中&#xff0c;圆与直线的交点仿佛散落的珍珠&#xff0c;而连接这些珍珠的线段之间&#xff0c;藏着一组令人惊叹的等量关系。当我们用直尺测量、用逻辑推导时&#xff0c;…

一文看懂显示接口:HDMI / DP / VGA / USB-C 有什么区别?怎么选?

刚买的新显示器&#xff0c;插上线却发现画面糊成马赛克&#xff1f;游戏打到关键时刻突然黑屏&#xff1f;4K电影看着看着就卡顿&#xff1f;别急&#xff01;这些问题很可能都是"接口没选对"惹的祸&#xff01;今天我们就来彻底搞懂HDMI、DP、VGA、USB-C这些常见的…

【ARM嵌入式汇编基础】- 操作系统基础(二)

操作系统基础(二) 文章目录 操作系统基础(二)6、线程7、进程内存管理8、内存页9、内存保护10、匿名内存和内存映射内存11、内存映射文件和模块6、线程 程序首次启动时,会创建一个新进程,并为该程序分配一个线程。该初始线程负责初始化进程并最终调用程序中的主函数。多线…

C#调用Matlab生成的DLL

C#调用Matlab生成的DLL 1.Matlab生成DLL文件1.1准备脚本文件1.2.输出DLL文件2.Winform项目中调用DLL2.1.创建Winform项目2.2.添加引用2.3.调用DLL2.3.1. 方法12.3.2. 方法22.4.配置CPU3.运行测试4.缺点1.Matlab生成DLL文件 1.1准备脚本文件 在Matlab环境下创建脚本文件calcul…

Julia爬取数据能力及应用场景

Julia 是一种高性能编程语言&#xff0c;特别适合数值计算和数据分析。然而&#xff0c;关于数据爬取&#xff08;即网络爬虫&#xff09;方面&#xff0c;我们需要明确以下几点&#xff1a;虽然它是一门通用编程语言&#xff0c;但它的强项不在于网络爬取&#xff08;Web Scra…

Java03 二维数组|方法

一、声明数组和初始化&#xff08;掌握&#xff09;数据类型[] 数组名 ; 数据类型 数组名[] ;静态初始化数据类型[] 数组名 {元素1,元素2,元素3};动态初始化数据类型[] 数组名 new 数据类型[5]; 数组名[0] 元素1;二、数组的内存结构&#xff08;掌握&#xff09;package…

1. JVM介绍和运行流程

1. jvm是什么JVM&#xff08;Java Virtual Machine&#xff09;是 Java 程序的运行环境&#xff0c;它是 Java 技术的核心组成部分&#xff0c;负责执行编译后的 Java 字节码&#xff08;.class文件&#xff09;。jvm 说白了就是虚拟机&#xff0c;一个专门运行java字节码文件的…