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

news2024/11/18 9:35:07
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.coloradmin.cn/o/1629846.html

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

相关文章

day-26 查询网格图中每一列的宽度

思路: 利用两个for循环,外层for用于遍历列数,内层for用于计算每一列的宽度 解题方法: 内层for循环时: 1.当前所在位置的值为0 则宽度为1 2.当前所在位置的值大于0 则宽度通过不断取商得到 3.当前所在位置的值大于0 则…

Vitis HLS 学习笔记--IDE软件高效操作指引

目录 1. 简介 2. 实用软件操作 2.1 C/RTL Cosimulation 选项 2.2 Do not show this dialog again 2.3 New Solution 2.4 对比 Solution 2.5 以命令行方式运行(windows) 2.6 文本缩放快捷键 2.7 查看和修改快捷键 2.8 将Vitis HLS RTL 导入 Viv…

SpikingJelly笔记之梯度替代

文章目录 前言一、梯度替代二、网络结构三、MNIST分类1、单步模式2、多步模式 总结 前言 在SpikingJelly使用梯度替代训练SNN,构建单层全连接SNN实现MNIST分类任务。 一、梯度替代 1、梯度替代: 阶跃函数不可微,无法进行反向传播 g ( x ) …

自动驾驶新书“五一”节马上上市了

我和杨子江教授合写的《自动驾驶系统开发》终于在清华大学出版社三校稿之后即将在五一节后出版。 清华大学汽车学院的李克强教授和工程院院士撰写了序言。 该书得到了唯一华人图灵奖获得者姚期智院士、西安交大管晓宏教授和科学院院士以及杨强教授和院士等的推荐,…

java:SpringBootWeb请求响应

Servlet 用java编写的服务器端程序 客户端发送请求至服务器 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器 服务器将响应返回给客户端 javaweb的工作原理 在SpringBoot进行web程序开发时,内置了一个核心的Servlet程序DispatcherServlet,称之…

前端用a标签实现静态资源文件(excel/word/pdf)下载

接上文实现的 前端实现将二进制文件流,并下载为excel文件后, 实际项目中一般都会有一个模版下载的功能,一般都由服务端提供一个下载接口,返回文件流或url地址,然后前端再处理成对应需要的类型的文件。 但是&#xff…

从3秒飞降至25毫秒:揭秘惊艳的接口优化策略!

大家好,最近看到京东云的一位大佬分享的接口优化方案,感觉挺不错的,拿来即用。建议收藏一波或者整理到自己的笔记本中,随时查阅! 下面是正文。 一、背景 针对老项目,去年做了许多降本增效的事情&#xf…

如何学习思考能力?如何训练思考能力?思考不一样?问到底 对新敏感 主动 不怕试错 预测 独特一套

简单易行的方法:问到底 一个简单而有效的方法是使用"五个为什么"技术。当面临问题时,反复问自己为什么,至少问五次,以深入了解问题的根本原因。这有助于培养深入思考和分析问题的能力。 对新敏感 学习思考能力的关键…

PotatoPie 4.0 实验教程(23) —— FPGA实现摄像头图像伽马(Gamma)变换

为什么要进行Gamma校正 图像的 gamma 校正是一种图像处理技术,用于调整图像的亮度和对比度,让显示设备显示的亮度和对比度更符合人眼的感知。Gamma 校正主要用于修正显示设备的非线性响应,以及在图像处理中进行色彩校正和图像增强。 以前&am…

JAVA 中间件之 Mycat2

Mycat2应用与实战教程 1.Mycat2概述 1.1 什么是MyCat 官网: http://mycatone.top/ Mycat 是基于 java 语言编写的数据库中间件,是一个实现了 MySQL 协议的服务器,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和…

1. 房屋租赁管理系统(基于springboot/vue的Java项目)

1.此系统的受众 1.1 在校学习的学生,可用于日常学习使用或是毕业设计使用 1.2 毕业一到两年的开发人员,用于锻炼自己的独立功能模块设计能力,增强代码编写能力。 1.3 亦可以部署为商化项目使用。 2. 技术栈 jdk8springbootvue2mysq5.7&8…

C++ 动态链接库DLL创建及使用

一、动态链接库DLL创建 使用VS2022 创建 1、创建新解决方案 创建即可 2、创建动态链接库新项目 右键解决方案 语言选择C,选择动态链接库 填入项目名称,勾选:将解决方案和项目放在同一目录中 点击创建 3、创建后,显示dllmai…

西湖大学赵世钰老师【强化学习的数学原理】学习笔记2节

强化学习的数学原理是由西湖大学赵世钰老师带来的关于RL理论方面的详细课程,本课程深入浅出地介绍了RL的基础原理,前置技能只需要基础的编程能力、概率论以及一部分的高等数学,你听完之后会在大脑里面清晰的勾勒出RL公式推导链条中的每一个部…

使用frp实现内网穿透教程

文章目录 简介frp 是什么?为什么选择 frp? 概念工作原理代理类型 内网穿透教程服务端安装和配置本地Windows(客户端)安装和配置本地Linux虚拟机(客户端)安装和配置使用 systemd 管理服务端注意事项 简介 f…

Odoo:全球排名第一的免费开源PLM管理系统介绍

概述 利用开源智造OdooPLM产品生命周期管理应用,重塑创新 实现产品生命周期管理数字化,高效定义、开发、交付和管理创新的可持续产品,拥抱数字化供应链。 通过开源智造基于Odoo开源技术平台打造数字化的产品生命周期管理(PLM&am…

MongoDB的安装(Linux环境)

登录到Linux服务器执行 lsb_release -a ,即可得知服务器的版本信息为:CentOS 7。 # CentOS安装lsb_release包 [rootlinux100 ~]# sudo yum install redhat-lsb# 查看Linux版本 [rootlinux100 ~]# lsb_release -a LSB Version: :core-4.1-amd64:core-…

redis7 for windows的安装教程

本篇博客主要介绍redis7的windows版本下的安装教程 1.redis介绍 Redis(Remote Dictionary Server)是一个开源的,基于内存的数据结构存储系统,可用作数据库、缓存和消息代理。它支持多种数据结构,如字符串、哈希表、列…

Django中的事务

1 开启全局的事务 DATABASES {default: {ENGINE: django.db.backends.mysql, # 使用mysql数据库NAME: tracerbackend, # 要连接的数据库USER: root, # 链接数据库的用于名PASSWORD: 123456, # 链接数据库的用于名HOST: 192.168.1.200, # mysql服务监听的ipPORT: 3306, …

四、OSPF域间路由

注:区域(area)是以接口进行划分的 描述: R1的g0/0/1接口属于area 0 √ R1属于区域0和区域1 1.设计原则 1、OSPF区域的设计原则: 骨干区域有且只能存在一个 非骨干区域必须和骨干区域相连 多区域时&#…

【Linux实践室】Linux文件打包和解压缩实战指南:tar打包命令操作详解(文末送书)

🌈个人主页:聆风吟_ 🔥系列专栏:Linux实践室、网络奇遇记 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 一. ⛳️任务描述二. ⛳️相关知识2.1 🔔打包2.1.1 👻知识点讲解2.1.2 &…