C++ 内存分配和管理(八股总结)
C++是如何做内存管理的(有哪些内存区域)?
(1)堆,使用malloc、free动态分配和释放空间,能分配较大的内存;
(2)栈,为函数的局部变量分配内存,能分配较小的内存;
(3)全局/静态存储区,用于存储全局变量和静态变量;
(4)常量存储区,专门用来存放常量;
(5)自由存储区:通过new和delete分配和释放空间的内存,具体实现可能是堆或者内存池。
补充:堆是C和操作系统的术语,自由存储区是C++的术语,指的是通过new和delete动态分配和释放对象的抽象概念;基本上C++也会用堆区实现自由存储,但程序员可以通过重载操作符,改用其他内存实现自由存储,比如全局变量做的对象池。
堆和栈的内存有什么区别?
(1)堆中的内存需要手动申请和手动释放,栈中内存是由OS自动申请和自动释放;
(2)堆能分配的内存较大(4G(32位机器)),栈能分配的内存较小(1M);
(3)在堆中分配和释放内存会产生内存碎片,栈不会产生内存碎片;
(4)堆的分配效率低,栈的分配效率高;
(5)堆地址从低向上,栈由高向下。
C++和C分别使用什么函数来做内存的分配和释放?有什么区别,能否混用?
C使用malloc/free,C++使用new/delete,前者是C语言中的库函数,后者是C++语言的运算符,对于自定义对象,malloc/free只进行分配内存和释放内存,无法调用其构造函数和析构函数,只有new/delete能做到,完成对象的空间分配和初始化,以及对象的销毁和释放空间,不能混用,具体区别如下:
(1)new分配内存空间无需指定分配内存大小,malloc需要;
(2)new返回类型指针,类型安全,malloc返回void*,再强制转换成所需要的类型;
(3)new是从自由存储区获得内存,malloc从堆中获取内存;
(4)对于类对象,new会调用构造函数和析构函数,malloc不会(核心)。
什么是内存对齐(字节对齐),为什么要做内存对齐,如何对齐?
(1)内存对齐的原因:关键在于CPU存取数据的效率问题。为了提高效率,计算机从内存中取数据是按照一个固定长度的。比如在32位机上,CPU每次都是取32bit数据的,也就是4字节;若不进行对齐,要取出两块地址中的数据,进行掩码和移位等操作,写入目标寄存器内存,效率很低。内存对齐一方面可以节省内存,一方面可以提升数据读取的速度;
(2)内容:内存对齐指的是C++结构体中的数据成员,其内存地址是否为其对齐字节大小的倍数。
(3)对齐原则:1)结构体变量的首地址能够被其最宽基本类型成员的对齐值所整除;2)结构体内每一个成员的相对于起始地址的偏移量能够被该变量的大小整除;3)结构体总体大小能够被最宽成员大小整除;如果不满足这些条件,编译器就会进行一个填充(padding)。
(4)如何对齐**:**声明数据结构时,字节对齐的数据依次声明,然后小成员组合在一起,能省去一些浪费的空间,不要把小成员参杂声明在字节对齐的数据之间。
#pragma pack 指令:这是一个编译器指令,用于控制结构体或联合体中成员的对齐。例如,#pragma pack(push, 1) 可以设置对齐为1字节,而 #pragma pack(pop) 则恢复到之前的对齐设置。
#pragma pack(push, 1)
struct MyStruct {char a; // 1 byteint b; // 4 bytes
};
#pragma pack(pop)
C++11 alignas 关键字:C++11 引入了 alignas 关键字,允许程序员显式指定变量或类型的最小对齐要求。
struct alignas(16) MyStruct {char a;int b;
};
这里,MyStruct 的实例将保证16字节对齐。
malloc、calloc、realloc、alloca
- malloc:申请指定字节数的内存。申请到的内存中的初始值不确定。
- calloc:为指定长度的对象,分配能容纳其指定个数的内存。申请到的内存的每一位(bit)都初始化为 0。
- realloc:更改以前分配的内存长度(增加或减少)。当增加长度时,可能需将以前分配区的内容移到另一个足够大的区域,而新增区域内的初始值则不确定。
- alloca:在栈上申请内存。程序在出栈的时候,会自动释放内存。但是需要注意的是,alloca 不具可移植性, 而且在没有传统堆栈的机器上很难实现。alloca 不宜使用在必须广泛移植的程序中。C99 中支持变长数组 (VLA),可以用来替代 alloca。
在 C++ 中,malloc、calloc、realloc 和 alloca 是动态内存分配函数,主要用于在运行时分配和管理内存。下面对它们分别进行定义、主要用途和区别分析。
1. malloc(Memory Allocation)
定义
malloc 函数用于分配指定大小的内存块,返回一个指向该内存块的指针,初始值为未定义(即未初始化)。
用途
- 用于在堆中分配内存。
- 适合需要明确大小但不需要初始化的内存场景。
示例代码
#include <cstdlib>
#include <iostream>int main() {int* ptr = (int*)malloc(5 * sizeof(int)); // 分配 5 个整型大小的内存块if (ptr == nullptr) {std::cout << "Memory allocation failed\n";return 1;}for (int i = 0; i < 5; ++i) {ptr[i] = i + 1; // 手动初始化}for (int i = 0; i < 5; ++i) {std::cout << ptr[i] << " ";}std::cout << "\n";free(ptr); // 释放内存return 0;
}
输出
1 2 3 4 5
2. calloc(Contiguous Allocation)
定义
calloc 用于分配指定数量的内存块,并将所有分配的内存初始化为零。
用途
- 适合需要分配连续的内存块且初始化为零的场景。
- 提高内存分配后的安全性。
示例代码
#include <cstdlib>
#include <iostream>int main() {int* ptr = (int*)calloc(5, sizeof(int)); // 分配 5 个整型大小的内存块并初始化为 0if (ptr == nullptr) {std::cout << "Memory allocation failed\n";return 1;}for (int i = 0; i < 5; ++i) {std::cout << ptr[i] << " "; // 输出已初始化为 0 的值}std::cout << "\n";free(ptr); // 释放内存return 0;
}
输出
0 0 0 0 0
3. realloc(Reallocation)
定义
realloc 用于调整之前分配的内存大小。它可能会移动原内存块到新的位置,返回新内存块的指针。
用途
- 动态调整已分配内存大小。
- 避免重新分配和手动复制数据。
示例代码
#include <cstdlib>
#include <iostream>int main() {int* ptr = (int*)malloc(3 * sizeof(int));if (ptr == nullptr) {std::cout << "Memory allocation failed\n";return 1;}for (int i = 0; i < 3; ++i) {ptr[i] = i + 1;}// 调整内存大小为 5ptr = (int*)realloc(ptr, 5 * sizeof(int));if (ptr == nullptr) {std::cout << "Memory reallocation failed\n";return 1;}for (int i = 3; i < 5; ++i) {ptr[i] = i + 1; // 初始化新分配的部分}for (int i = 0; i < 5; ++i) {std::cout << ptr[i] << " ";}std::cout << "\n";free(ptr);return 0;
}
输出
1 2 3 4 5
4. alloca(Allocate on Stack)
定义
alloca 用于在栈上分配内存,分配的内存在函数返回后会自动释放。
用途
- 用于短期内存分配,避免显式释放。
- 適合临时数据的内存管理。
示例代码
#include <cstdlib>
#include <iostream>int main() {int* ptr = (int*)alloca(5 * sizeof(int)); // 分配 5 个整型大小的内存块在栈上for (int i = 0; i < 5; ++i) {ptr[i] = i + 1;}for (int i = 0; i < 5; ++i) {std::cout << ptr[i] << " ";}std::cout << "\n";// 不需要调用 freereturn 0;
}
输出
1 2 3 4 5
区别分析
| 特性 | malloc | calloc | realloc | alloca |
|---|---|---|---|---|
| 分配位置 | 堆 | 堆 | 堆 | 栈 |
| 是否初始化 | 否 | 是(初始化为 0) | 保持原始数据,扩展部分未初始化 | 否(与 malloc 类似) |
| 内存调整 | 不支持 | 不支持 | 支持 | 不支持 |
| 释放方式 | 手动调用 free | 手动调用 free | 手动调用 free | 自动释放 |
malloc、free
用于分配、释放内存
malloc、free 使用
申请内存,确认是否申请成功
char *str = (char*) malloc(100);
assert(str != nullptr);
释放内存后指针置空
free(p);
p = nullptr;
new、delete
- new / new[]:完成两件事,先底层调用 malloc 分配了内存,然后调用构造函数(创建对象)。
- delete/delete[]:也完成两件事,先调用析构函数(清理资源),然后底层调用 free 释放空间。
- new 在申请内存时会自动计算所需字节数,而 malloc 则需我们自己输入申请内存空间的字节数。
new、delete 使用
申请内存,确认是否申请成功
int main()
{T* t = new T(); // 先内存分配 ,再构造函数delete t; // 先析构函数,再内存释放return 0;
}
相关文章:
C++ 内存分配和管理(八股总结)
C是如何做内存管理的(有哪些内存区域)? (1)堆,使用malloc、free动态分配和释放空间,能分配较大的内存; (2)栈,为函数的局部变量分配内存,能分配…...
如何使用 JSONP 实现跨域请求?
以下是使用 JSONP 实现跨域请求的步骤: 实现步骤: 1. 客户端设置 在客户端,你需要创建一个 <script> 标签,并将其 src 属性设置为跨域请求的 URL,并添加一个 callback 参数。这个 callback 参数将包含一个函数…...
【机器学习实战入门】基于深度学习的乳腺癌分类
什么是深度学习? 作为对机器学习的一种深入方法,深度学习受到了人类大脑和其生物神经网络的启发。它包括深层神经网络、递归神经网络、卷积神经网络和深度信念网络等架构,这些架构由多层组成,数据必须通过这些层才能最终产生输出。…...
Flowable 管理各业务流程:流程设计器 (获取流程模型 XML)、流程部署、启动流程、流程审批、流程挂起和激活、任务分配
文章目录 引言I 表结构主要表前缀及其用途核心表II 流程设计器(Flowable BPMN模型编辑器插件)Flowable-UIvue插件III 流程部署部署步骤例子:根据流程模型ID部署IV 启动流程启动步骤ACT_RE_PROCDEF:流程定义相关信息例子:根据流程 ID 启动流程V 流程审批审批步骤Flowable 审…...
Kafka 日志存储 — 日志索引
每个日志分段文件对应两个索引文件:偏移量索引文件用来建立消息偏移量到物理地址之间的映射;时间戳索引文件根据指定的时间戳来查找对应的偏移量信息。 1 日志索引 Kafka的索引文件以稀疏索引的方式构造消息的索引。它并不保证每个消息在索引文件中都有…...
【大模型】ChatGPT 高效处理图片技巧使用详解
目录 一、前言 二、ChatGPT 4 图片处理介绍 2.1 ChatGPT 4 图片处理概述 2.1.1 图像识别与分类 2.1.2 图像搜索 2.1.3 图像生成 2.1.4 多模态理解 2.1.5 细粒度图像识别 2.1.6 生成式图像任务处理 2.1.7 图像与文本互动 2.2 ChatGPT 4 图片处理应用场景 三、文生图操…...
OceanBase 社区年度之星专访:北控水务纪晓东,社区铁杆开发者
编者按:作为开源数据库,社区的发展和持续进步,来自于每一位贡献者的智慧与支持。2024年度,OceanBase社区特别设立了“年度之星”奖,以表彰和感谢在过去一年中,为社区发展作出突出贡献的朋友。 今日&#x…...
Docker 实现MySQL 主从复制
一、拉取镜像 docker pull mysql:5.7相关命令: 查看镜像:docker images 二、启动镜像 启动mysql01、02容器: docker run -d -p 3310:3306 -v /root/mysql/node-1/config:/etc/mysql/ -v /root/mysql/node-1/data:/var/lib/mysql -e MYS…...
农业农村大数据应用场景|珈和科技“数字乡村一张图”解决方案
近年来,珈和科技持续深耕农业领域,聚焦时空数据服务智慧农业。 珈和利用遥感大数据、云计算、移动互联网、物联网、人工智能等先进技术,搭建“天空地一体化”监测体系,并创新建设了150的全球领先算法模型,广泛应用于高…...
doris 2.1 Queries Acceleration-Hints 学习笔记
1 Hint Classification 1.1 Leading Hint:Specifies the join order according to the order provided in the leading hint. 1.2 Ordered Hint:A specific type of leading hint that specifies the join order as the original text sequence. 1.3 Distribute Hint:Speci…...
STM32 FreeRTOS 任务挂起和恢复---实验
实验目标 学会vTaskSuspend( )、vTaskResume( ) 任务挂起与恢复相关API函数使用: start_task:用来创建其他的三个任务。 task1:实现LED1每500ms闪烁一次。 task2:实现LED2每500ms闪烁一次。 task3:判断按键按下逻辑,KE…...
Ubuntu 24.04 LTS 通过 docker desktop 安装 seafile 搭建个人网盘
准备 Ubuntu 24.04 LTSUbuntu 空闲硬盘挂载Ubuntu 安装 Docker Desktop [我的Ubuntu服务器折腾集](https://blog.csdn.net/jh1513/article/details/145222679。 安装 seafile 参考资料 Docker安装 Seafile OnlyOffice 并配置OnlyOffice到Seafile,实现在线编辑…...
Open3D 最小二乘拟合平面(直接求解法)【2025最新版】
目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 博客长期更新,本文最近更新时间为:2025年1月18日。 一、算法原理 平面方程的一般表达式为:...
【CC2640R2F】香瓜CC2640R2F之SPI读写W25Q80
本文最后修改时间:2022年01月08日 10:45 一、本节简介 本节以simple_peripheral工程为例,介绍如何使用SPI读写W25Q80(外部flash)。 二、实验平台 1)CC2640R2F平台 ①协议栈版本:CC2640R2 SDK v1.40.00.4…...
探秘Shortest与Stagehand:开启高效测试与自动化新篇
探秘Shortest与Stagehand:开启高效测试与自动化新篇 在数字化浪潮的推动下,网页自动化工具如同繁星般涌现,为众多行业带来了效率的变革。在这些工具中,Shortest和Stagehand凭借其出色的表现,成为了众多开发者、测试人…...
llama 3 笔记
0.简介 llama 3 是在 15 万亿个 Token 上预训练的语言模型,具有 8B 和 70B 两种参数规模,可以支持广泛的用户场景,在各种行业基准上取得了最先进的性能,并提供了一些新功能,包括改进的推理能力。 1.改进亮点 参数规模与模型架构:Llama 3提供了8B和70B两种参数规模的模…...
写作利器:如何用 PicGo + GitHub 图床提高创作效率
你好呀,欢迎来到 Dong雨 的技术小栈 🌱 在这里,我们一同探索代码的奥秘,感受技术的魅力 ✨。 👉 我的小世界:Dong雨 📌 分享我的学习旅程 🛠️ 提供贴心的实用工具 💡 记…...
【文件篇】11.磁盘文件系统
上一篇博客中我们介绍到如果我们要访问文件首先需要打开这个文件,而文件是在磁盘上存储的,也就是说需要在磁盘上找到这个文件的路径。但是磁盘上有很多文件,这些文件都有自己的路径的,这些文件还有内容和属性,它们都是…...
嵌入式产品级-超小尺寸热成像相机(从0到1 硬件-软件-外壳)
Thermal_Imaging_Camera This is a small thermal imaging camera that includes everything from hardware and software. 小尺寸热成像相机-Pico-LVGL-RTOS 基于RP2040 Pico主控与RTOS,榨干双核性能实现LVGL和成图任务并行。ST7789驱动240280屏,CST8…...
三维扫描赋能文化:蔡司3D扫描仪让木质文化遗产焕发新生-沪敖3D
挪威文化历史博物馆在其修复工作中融入现代3D扫描技术,让数百年的历史焕发新生。 文化历史博物馆的工作 文化历史博物馆是奥斯陆大学的一个院系。凭借其在文化历史管理、研究和传播方面的丰富专业知识,该博物馆被誉为挪威博物馆研究领域的领先机构。馆…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
