C++高级特性:C/C++内存结构模型(十一)

embedded/2024/10/18 16:54:55/
1、内存结构
  • C/C++语言一只被认为是一种底层语言,与其他语言不一样,对内存结构理解是C/C++程序员从入门到入土的开端。

  • 其他编程语言对内存管理是透明的,程序员无序关心可以认为是一个黑盒;而C/C++不一样理解好内存结构有利于编写健壮性的代码

  • C++的内存结构主要涉及以下区域

    • 代码区:存储程序的机器码指令,包括执行程序和只读数据:全局常量、const修饰的变量、字符串常量
    • 全局/静态存储区:存储全局变量和静态变量,其生命周期贯穿整个程序执行过程的变量!
    • 堆区:用于动态分配内存,存储在堆上的数据的生命周期由程序员自行管理(地址由低到高)
    • 内存映射区:mmap共享映射区,主要包括动态库.dll/.so、文件映射、匿名映射
    • 栈区:用于存储函数调用信息、局部变量、临时数据等,遵循后进先出的原则(地址由高到低)
      在这里插入图片描述
2、内存各区介绍
  1. 代码段可制度数据段通常在程序加载时有操作系统加载到内存,一旦加载就不能被修改
  2. 在函数调用时,函数的机器码也存储在代码段中,每个函数有其独特的代码段地址
  3. 字符串常量等只读数据段中的数据是不可修改的,任何企图修改这些数据的尝试都会导致运行时错误
2.1、代码区
  • 在C++程序中,代码区是存储程序执行代码的一部分内存区域。它通常被划分为两个主要部分:代码段(.text)和只读数据段(.rodata)
  • 这里说的代码区是指已经运行并且加载到内存中的可执行的二进制指令,并不是存储在磁盘上的源代码文件
2.1.1、代码段(.text)
  • 结构:代码段存储程序的可执行指令,即机器码。这是程序中实习执行的代码部分。
  • 使用场景:包括程序的函数、方法、控制流等。这部分内存是只读的,程序在运行时不能修改代码段的内容
2.1.2、只读数据段(.rodata)
  • 只读数据段:rodata是read-only data的缩写
  • 结构:只读数据段存储常量数据,例如字符串常量,以及全局或静态变量的初始化值。
  • 使用场景:用于存储不可修改的数据。字符串字面量是一个常见的只读数据段的例子
2.1、小结

代码区有两个很重要的特性:

  • 只读(read only):代码区的东西都是只读的,这意味着程序在运行时这部分的内容不被修改,有助于保证程序执行区间的数据的一致性和安全性
  • 可复用性(Sharable):代码区的内容通常是共享的,有趋势对于相同的程序的多个实例或同时运行起来的多个程序来说,多个程序实例可以共享相同的机器码,有助于节省内存

这些特点使得代码区能够更有效地支持多个程序的并发执行,并在运行时提供一定程序的保护,确保代码和只读数据的完整性。

2.2、全局/静态存储区

全局/静态存储区是程序中用于存储全局变量和静态变量的内存区域。这些变量在程序的整个声明周期内存在,并且其内存分配发生在程序启动时,知道程序结束。全局/静态存储区包括两个主要部分:全局变量区和静态变量区。

  • .data段
    • 已初始化的全局变量、静态变量存放在.data段。
    • .data段占用可执行文件空间,其内容有程序初始化。
  • .bss段
    • 未初始化的全局变量、静态变量存放在.bss段。
    • 初始化为0的全局变量、静态变量存放在.bss段。
    • .bss段不占用可执行文件空间,其内容由操作系统初始化。
  • 注意事项:
    • 全局、静态存储区的数据在程序启动时分配,在程序结束时释放
    • 全局变量区的数据可以被整个程序访问,而静态变量区的数据访问权限与其定义的位置有关。
    • 多线程访问,全局变量和静态变量可能需要额外的同步/互斥机制,以确保多个线程对它们的安全访问。
2.3、堆区
  • 堆区是程序运行时用于动态分配内存的一种内存区域,也称为自由存储区。
  • 堆上的内存可以在运行时动态分配和释放,由程序员自行负责管理其生命周期
  • 使用场景
    • 堆是有操作系统分配的一块较大的内存区域,可以分配出较大的一块虚拟内存连续的地址
    • 动态内存分配:当程序无法确定需要多少内存时或者需要在程序的不同部分共享数据时,使用堆上的内存非常有用
    • 对象的动态创建和销毁:使用new 和 malloc操作符分配的内存,使用delete和free操作释放相应的内存。
2.4、栈区
  • 使用场景:
    • 存储函数的局部变量:酶促函数调用时,其局部变量被分配到栈上,函数返回时将这些变量自动释放
    • 存储函数的调用信息:每次函数调用时,函数的地址和一些其他信息被压入栈中,函数返回时再从栈中弹出这些信息
  • 栈帧:
    • 在函数调用时,一个栈帧(Stack Frame)被压入栈中。
    • 栈帧包含了函数的局部变量、返回值地址和其他与函数调用相关的信息。
    • 栈帧主要是通过寄存器地址偏移来实现的。
  • 栈的管理通常有编译器负责。编译器根据程序的结构和函数调用关系来分配和管理栈空间。在编译阶段,编译器会生成一些代码来处理栈的操作,包括栈帧的创建和销毁,局部变量的分配和释放,以及函数调用时的相关操作
    • 分析函数调用关系:编译器需要了解程序中函数的调用关系,以便正确生成栈帧和处理函数调用时的参数传递和返回值
    • 分配栈空间:对于每个函数,编译器需要决定分配多少空间用于栈帧,以容纳局部变量、函数操作、返回地址等
    • 生成栈操作指令:编译器会生成相同的汇编或机器码指令,用于执行栈的压栈和出栈操作,以及处理函数调用时的栈操作

高级语言中一般不需要管理栈帧的操作,在低级(汇编)语言中,程序员有更多的控制权,可以直接操作栈,高级语言中这种底层的栈帧操作通常有编译器自动处理。

2.5、内存映射区
  • 这个区域很灵活主要负责:
    • 动态库:windows下的.dll库、Linux下的.so库的加载与库调用
    • 共享内存映射、文件映射的处理
    • malloc分配超过128k也会进入内存映射区进行分配空间
    • 其分配方向不同:32位和64位分配的方向相反
2.6、内核空间
  • 所有程序共享的一个空间

  • 用户代码不能读写的一段地址

3、总结
  • 作为一个专业的C++使用者来说,清楚的知道自己的代码变量存储的区域会有非常大的好处,补单能够写出高性能代码,而且有助于减少一些深层次的BUG。

  • 使用C++内存的一些注意事项

    • 内存泄漏:确保在动态分配内存后找个合适的时机释放掉,避免出现内存泄漏

    • 野指针:注意在指针使用后及时置为nullptr,避免访问已经释放的内存

    • 栈溢出:谨慎使用递归或者在栈区使用巨大的空间分配局部变量,以免造成栈溢出

    • 悬挂指针:避免悬挂指针的问题,即指向已经释放的内存区域

    • 智能指针:考虑使用C++的智能指针(std::unique_ptr、std::shared_ptr),提高内存管理的安全性和便利性。

    • 局部变量生命周期:理解局部变量的生命周期,确保在离开其作用域前不在访问。


http://www.ppmy.cn/embedded/20824.html

相关文章

leetcode 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2示例 2: 输入…

推荐3个视频转文字的工具

如果是长视频转文字的话,我会推荐你三个专业的能够将视频文字提取出来的工具,操作无门槛,转换出的文字准确率高,可以直接导出文字。 1.一键识别王 https://www.xunjiepdf.com/yijianshibiewang 专业的图片文字识别软件&#xff0…

vue 项目关于不同分辨率的电脑网页适配方案

流式布局:这是一种相对灵活的布局方式,页面的元素宽度使用相对宽度(例如百分比)来定义,而不是使用绝对宽度(例如像素)。这样,当浏览器窗口大小变化时,元素会自动调整大小…

04.JAVAEE之线程2

1.线程的状态 1.1 观察线程的所有状态 线程的状态是一个枚举类型 Thread.State public class ThreadState {public static void main(String[] args) {for (Thread.State state : Thread.State.values()) {System.out.println(state);}} } NEW:Thread 对象已经有了.start 方…

设置Mac上Git的多账户配置,用于同时访问GitLab和Gitee

在 Mac 上配置 Git 多账户(比如 GitLab 和 Gitee)的步骤如下: 1. 生成 SSH 密钥 首先,你需要为每个 Git 服务生成一个 SSH 密钥。在终端中运行以下命令,然后按照提示操作: ssh-keygen -t rsa -C "y…

Gateway服务网关!!!

一、为什么需要服务网关&#xff1a; 两大特性&#xff1a;高可用和高性能 1、高性能&#xff1a;采用异步的方式调用服务。 2、高可用 二、网关包含三大属性&#xff1a; 三、基本配置 <dependency><groupId>org.springframework.boot</groupId><artif…

[最新]访问/加速StackOverFlow的方法

但是有很多问题都是在StackOverFlow上有现成的解决方案&#xff0c;而某度搜索引擎…前一页的回答互相抄袭&#xff0c;看着实在胀眼睛。 话不多说&#xff0c;解决办法&#xff1a; 直接访问插件商店下载插件&#xff08;最快捷方便&#xff0c;点点就行&#xff09;&#x…

mPEG-Biotin,Methoxy PEG Biotin在免疫亲和层析、荧光标记和生物传感器等领域发挥关键作用

【试剂详情】 英文名称 mPEG-Biotin&#xff0c;Methoxy PEG Biotin 中文名称 聚乙二醇单甲醚生物素&#xff0c;甲氧基-聚乙二醇-生物素 外观性状 由分子量决定&#xff0c;固体或者粘稠液体。 分子量 0.4k&#xff0c;0.6k&#xff0c;1k&#xff0c;2k&#xff0c;3.…