C++ 数据内存分布揭秘:从栈到堆的探索之旅

news2024/11/28 8:41:30

目录

1. 栈(Stack)

2. 堆(Heap)

malloc和new的区别

堆与栈在C++中的异同点详解

3. 数据段(Data Segment)

4. 代码段(Code Segment)

5. 动态内存分配的陷阱


当我们谈论C++编程时,对内存布局的理解至关重要。本文将深入探讨C++中各种变量和数据结构在内存中的分布情况,包括栈(stack)、堆(heap)以及其他内存区域,并通过多个代码示例直观呈现这些概念的实际应用。

1. 栈(Stack)

栈是一种快速高效的内存区域,由编译器自动管理。每当函数被调用时,函数的局部变量和临时变量都会在栈上分配空间,函数执行完毕后,这些空间将自动释放。

void functionExample() {
    int localVar = 10; // 局部变量存储在栈上
    char str[] = "Hello, Stack!"; // 本地数组也存储在栈上
}

int main() {
    functionExample(); // 调用函数时,局部变量在栈上分配和释放
}

2. 堆(Heap)

堆则是用于动态内存分配的区域,程序员可以通过`new`或`malloc`函数申请内存,通过`delete`或`free`函数释放内存。堆内存的分配和释放由程序员手动控制,相较于栈更灵活但也更容易产生内存泄漏。

int main() {
    int* heapVar = new int(20); // 动态分配的整型变量存储在堆上
    char* heapArray = new char[100]; // 动态分配的字符数组存储在堆上

    delete heapVar;
    delete[] heapArray; // 必须手动释放堆上的内存
}
malloc和new的区别

mallocnew 都是用来在程序运行时动态分配内存的机制,但它们之间存在一些关键性的区别,这些区别主要源于它们各自的设计初衷和功能特性:

  1. 来源和适用语言:

    • malloc 是 C 语言标准库函数,位于 <stdlib.h> 头文件中。

    • new 是 C++ 关键字,是 C++ 语言特有的内存管理机制。

  2. 内存分配与类型关联:

    • malloc 需要开发者指定内存分配的大小(以字节为单位),返回的是 void* 类型的指针,需要手动类型转换为所需类型。

    • new 则可以根据类型自动计算所需内存大小,例如 int* ptr = new int;,编译器知道一个 int 类型需要多少内存,所以不需要指定大小。new 返回的是相应类型的指针,无需额外类型转换。

  3. 构造函数和析构函数调用:

    • malloc 只负责分配内存,不执行任何构造函数,对于非 POD(Plain Old Data)类型(如带有构造函数的类),单纯使用 malloc 分配内存不足以初始化对象。

    • new 在分配内存的同时还会调用相应类型的构造函数初始化对象,而当使用 delete 释放内存时,会调用对象的析构函数完成必要的清理工作。

  4. 错误处理:

    • 如果 malloc 分配内存失败,会返回 NULL,需要程序员检查返回值判断是否分配成功。

    • new 在分配内存失败时会抛出 std::bad_alloc 异常,而不是简单地返回 NULL,这对于异常安全编程更加友好。

  5. 内存释放:

    • 使用 malloc 分配的内存需使用 free 函数来释放。

    • 使用 new 分配的内存则需使用 delete 或 delete[](对于数组)来释放。

  6. 重载操作符:

    • C++ 允许重载 new 和 delete 操作符,使得内存管理更为灵活,可以定制内存分配和释放的行为。

    • malloc 和 free 函数本身是不可以被重载的。

  7. 内存对齐和调试支持:

    • new 在分配内存时会考虑到对象的内存对齐要求,确保分配的内存满足目标平台的对齐约束。

    • new 还可以提供调试版本,比如 _DEBUG 宏定义开启时,Visual Studio 提供的 debug 版本 new 会记录分配信息,方便调试内存泄漏等问题。

总之,malloc 更接近底层,提供了基础的内存分配功能;而 new 是 C++ 中的高级抽象,除了分配内存外,还负责初始化和清理对象,具有更好的类型安全性,并且能更好地融入面向对象编程的环境。在 C++ 编程中,除非有特别的理由,一般推荐使用 newdelete 来进行内存管理。

在C++中的异同点详解

相同点:

  1. 均属于内存区域:堆和栈都是C++程序运行时使用的内存区域,都是为了存储程序运行过程中的数据。

  2. 参与程序执行流程:无论是栈上的局部变量还是堆上动态分配的对象,都直接参与到程序的执行过程中,对程序的运行状态有着直接影响。

不同点:

栈(Stack)

  • 自动管理:栈内存由编译器自动分配和释放,程序员无须手动介入。当函数调用发生时,栈帧(包含局部变量、函数参数等)自动压入栈;函数执行完毕,栈帧自动弹出并释放内存。

  • 分配效率:栈内存分配速度较快,通常不存在内存碎片问题。

  • 大小限制:栈内存大小有限制且相对较小,超出限制可能导致栈溢出错误。

  • 生命周期:栈上变量的生命周期与所属函数的执行期一致,函数结束时,所有局部变量随之消亡。

  • 存储内容:栈主要用于存储函数参数、局部变量、临时对象等。

堆(Heap)

  • 手动管理:堆内存由程序员通过newmalloc等函数动态申请,通过deletefree等函数手动释放。如果忘记释放,将会导致内存泄漏。

  • 分配效率:堆内存分配较慢,需要查找合适的内存区域,并有可能引发内存碎片。

  • 大小可变:堆内存大小相对于栈更大,没有预设的大小限制,可以根据程序需求动态调整。

  • 生命周期:堆上动态分配的对象生命期直到程序员显式释放为止,不受函数调用的影响。

  • 存储内容:堆主要用于存储动态分配的对象、大尺寸数组和其他需要长期存在的数据结构。

  • 碎片问题:频繁的动态内存分配和释放可能导致堆内存碎片化,降低内存利用率。

总结起来,栈内存适用于短期、快速分配和释放的小规模数据,而堆内存更适合用于存储大尺寸或生命周期不确定的数据。理解两者之间的差异对于编写高性能、稳定且不易出错的C++程序至关重要。

3. 数据段(Data Segment)

数据段又分为初始化数据段(Data Segment)和未初始化数据段(BSS Segment)。初始化全局变量和静态变量存储在初始化数据段,未初始化全局变量和静态变量存储在未初始化数据段,并在程序启动时自动清零。

int globalVar = 10; // 初始化全局变量存放在数据段
static int staticGlobalVar = 20; // 静态全局变量同样存放在数据段

void Test() {
    static int staticVar = 30; // 静态局部变量也在数据段
}

4. 代码段(Code Segment)

代码段存放程序的机器指令和常量字符串。例如:

void someFunction() {}

int main() {
    const char* pConstStr = "Hello, Code Segment!"; // 字符串字面量存放在代码段
    someFunction(); // 函数的机器指令也在代码段
}

5. 动态内存分配的陷阱

频繁在堆上进行动态内存分配可能导致内存碎片。例如:

void dynamicMemoryTest() {
    for (int i = 0; i < 1000; ++i) {
        int* p = new int[i % 100]; // 不规则的内存分配可能产生内存碎片
        delete[] p;
    }
}

通过以上介绍和代码示例,我们对C++中内存分布有了更直观的认识。了解这些基础知识有助于我们在设计程序时更好地管理和优化内存使用,减少不必要的性能损失和潜在的内存泄漏风险。在实践中,合理结合栈、堆以及其他内存区域的特点,将有助于编写出高效、健壮的C++应用程序。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

指代消解类方法梳理

概念&#xff1a; MLM&#xff1a;带遮罩的语言模型 NSP&#xff1a;单句预测&#xff0c;任务包括两个输入序列 SBO&#xff1a;分词边界目标 1.spanBERT&#xff0c;2019 spanBERT是对bert从分词到文本跨度的优化&#xff0c;主要有两方面的优化&#xff1a;&#xff08…

Android OTA 交流群 2024 年 4 月问题汇总

Android OTA 交流群 2024 年 4 月问题汇总 相关文章 Android OTA 问题交流微信群和知识星球Android OTA 交流群 2024 年 4 月问题汇总Android OTA 交流群 2024 年 3 月问题汇总Android OTA 交流群 2024 年 2 月问题汇总Android OTA 交流群 2024 年 1 月问题汇总 问题汇总 2…

[蓝桥杯]真题讲解:班级活动(贪心)

[蓝桥杯]真题讲解&#xff1a;班级活动&#xff08;贪心&#xff09; 一、视频讲解二、正解代码1、C2、python33、Java 一、视频讲解 [蓝桥杯]真题讲解&#xff1a;班级活动&#xff08;贪心&#xff09; 二、正解代码 1、C #include<bits/stdc.h> using namespace st…

就业班 第三阶段(redis) 2401--5.7 day2 redis2 哨兵(前提是做好了主从)+redis集群

1、设置密码&#xff08;redis&#xff09; 先在redis.conf里面找到这个 后面写上要设置的密码即可 2、哨兵模式 监控redis集群中master状态的的工具 在做了主从的前提下 主 从1 从2 作用 1)&#xff1a;Master状态检测 2)&#xff1a;如果Master异常&#xff0c;则会进行…

【busybox记录】【shell指令】uniq

目录 内容来源&#xff1a; 【GUN】【uniq】指令介绍 【busybox】【uniq】指令介绍 【linux】【uniq】指令介绍 使用示例&#xff1a; 去除重复行 - 默认输出 去除重复行 - 跳过第n段&#xff08;空格隔开&#xff09;&#xff0c;比较n1以后的内容&#xff0c;去重 去…

RT-DETR-20240507周更说明|更新Inner-IoU、Focal-IoU、Focaler-IoU等数十种IoU计算方式

RT-DETR改进专栏|包含主干、模块、注意力、损失函数等改进 专栏介绍 本专栏包含模块、卷积、检测头、损失等深度学习前沿改进,目前已有改进点70&#xff01;每周更新。 20240507更新说明&#xff1a; ⭐⭐ 更新CIoU、DIoU、MDPIoU、GIoU、EIoU、SIoU、ShapeIou、PowerfulIoU、…

【C/C++】设计模式——单例模式

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

【从零开始学习Minio | 第一篇】快速介绍什么是Minio

前言&#xff1a; 在当今数字化时代&#xff0c;数据的存储和管理已经成为了企业发展中的关键一环。随着数据量的不断增长和数据安全性的日益受到重视&#xff0c;传统的数据存储解决方案往往面临着诸多挑战。为了应对这些挑战&#xff0c;云存储技术应运而生&#xff0c;并在…

【漏洞复现】CData API Server 路径遍历漏洞(CVE-2024-31849)

0x01 产品简介 CData API Server是CData公司的一个强大的数据连接平台&#xff0c;旨在帮助企业轻松地访问、整合和分析各种数据源。 0x02 漏洞概述 CData API Server 23.4.8846之前版本存在安全漏洞&#xff0c;该漏洞源于存在路径遍历漏洞。攻击者可利用该漏洞获得对应用程…

如何用TONGYILingma进行AI辅助编程?

通义灵码&#xff0c;是阿里云出品的一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等能力&#xff0c;并针对阿里云的云服务使用场景调优&#xff0c…

[Maven]IDEA报错-xxx is referencing itself

在IDEA中&#xff0c;执行 mvn clean时报错xxx is referencing itself。 解决方案&#xff1a;https://stackoverflow.com/questions/64246267/maven-error-using-intellij-is-referencing-itself 具体做法&#xff1a;采用上图第二条&#xff0c;将父模块pom文件中的对子模块…

《十八》QThread多线程组件

本章将重点介绍如何运用QThread组件实现多线程功能。 多线程技术在程序开发中尤为常用&#xff0c;Qt框架中提供了QThread库来实现多线程功能。当你需要使用QThread时&#xff0c;需包含QThread模块&#xff0c;以下是QThread类的一些主要成员函数和槽函数。 成员函数/槽函数 …

Skywalking数据持久化与自定义链路追踪

学习本篇文章之前首先要了解一下Sky walking的基础知识 分布式链路追踪工具Skywalking详解 一&#xff0c;Sky walking数据持久化 Sky walking提供了es&#xff0c;MySQL等数据持久化方案&#xff0c;默认使用h2基于内存的数据库&#xff0c;重启之后数据即会丢失。 在实际工…

streamlit通过子目录访问

运行命令&#xff1a; streamlit hello 系统默认使用8501端口启动服务&#xff1a; 如果想通过子目录访问服务&#xff0c;可以这么启动服务 streamlit hello --server.baseUrlPath "app" 也可以通过以下命令换端口 streamlit hello --server.port 9999 参考&…

【每日刷题】Day33

【每日刷题】Day33 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 2. 445. 两数相加 II - 力扣&#xff08;…

error code [1449]; The user specified as a definer (‘root‘@‘%‘) does not exist

其实就是说我的root用户权限不够&#xff0c;那就要加上权限&#xff0c;网上其他地方也有好多处理办法&#xff0c;但是要注意数据库版本。我用的是MySQL8.0.32版本&#xff0c;我是这样处理的&#xff0c;简单可行&#xff1a; GRANT ALL ON *.* TO root% ;FLUSH PRIVILEGES…

关系型数据库MySQL开发要点之多表设计案例详解代码实现

什么是多表设计 项目开发中 在进行数据库表结构设计时 根据数据模型和业务关系 会根据业务需求和业务模块之间的关系分析设计表结构 由于业务之间互相关联 所以表结构之间也存在着各种联系 主要分为以下三种 一对多 每个部门下是有多个员工的 但是一个员工只能归属一个部…

Penpad再获 Presto Labs 投资,Scroll 生态持续扩张

​Penpad 是 Scroll 生态的 LaunchPad 平台&#xff0c;其整计划像收益聚合器以及 RWA 等功能于一体的综合性 Web3 平台拓展&#xff0c;该平台在近期频获资本市场关注&#xff0c;并获得了多个知名投资者/投资机构的支持。 截止到本文发布前&#xff0c;Penpad 已经获得了包括…

Excel数据分析之动态图表

在日常办公中&#xff0c;可以用透视表和切片器的组合方式&#xff0c;制作动态图&#xff0c;以直观的方式展示年度、季度&#xff0c;和不同区域的销售额。 通过结合使用这两个工具&#xff0c;您可以创建动态图表&#xff0c;可根据您的选择实时更新。这对于快速了解数据并…

【busybox记录】【shell指令】comm

目录 内容来源&#xff1a; 【GUN】【comm】指令介绍 【busybox】【comm】指令介绍 【linux】【comm】指令介绍 使用示例&#xff1a; 逐行比较两个排序后的文件 - 默认输出 逐行比较两个排序后的文件 - 如果一个文件的排序有问题&#xff0c;那么反错&#xff08;默认&…