Linux系统下C++程序运行时的内存布局详解。【C++】

Linux系统下C++程序的虚拟内存模型。

  • 1.程序代码段
    • 存储内容
    • 生命周期
    • 初始化时机
    • 特点
    • 代码演示
  • 2.只读初始化数据段
    • 存储内容
    • 生命周期
    • 初始化时机
    • 特点
    • 代码演示
  • 3.读写初始化数据段
    • 存储内容
    • 生命周期
    • 初始化时机
    • 特点
    • 代码演示
  • 4. 堆区(Heap)
    • 存储内容
    • 生命周期
    • 初始化时机
    • 特点
    • 代码演示
  • 5. 栈区(Stack)
    • 存储内容
    • 生命周期
    • 初始化时机
    • 特点
    • 代码演示
  • 6.命令行参数
    • 存储内容
    • 生命周期
    • 初始化时机
    • 特点
    • 代码演示
  • 7.环境变量
    • 存储内容
    • 生命周期
    • 初始化时机
    • 特点
    • 代码演示

在Linux系统下,一个C++程序运行时的内存布局是从低地址到高地址组织的。下面是各个内存区域的详细说明,包括它们存储的信息以及这些信息的生命周期:

1.程序代码段

存储内容

  1. 存储CPU能够执行的程序的机器指令。包括程序的自定义函数和库函数(包括静态库和动态库)编译后的机器代码。
  2. 静态库:编译时整合到可执行文件。
  3. 动态库(Linux 下的 .so 文件,Windwos 下的 .dll 文件):程序运行时被加载到内存。

生命周期

开始:程序代码段的内容开始执行。
结束:程序代码段的内容执行结束。

初始化时机

不涉及。

特点

程序运行时,代码段只读。

代码演示

不涉及。

2.只读初始化数据段

存储内容

编译时已知且运行时不需要修改的数据。
const char * 指针指向的字符串。
const 修饰的全局或命名空间作用域内的基本数据类型变量。

生命周期

开始:程序开始执行时。
结束:程序执行结束后由操作系统回收。

初始化时机

程序启动时完成,main函数执行之前。

特点

只读初始化数据段通常被操作系统设置为只读。这意味着任何试图修改这一区域的数据的操作都将导致运行时错误(例如,违反访问权限的错误)。

代码演示

#include <iostream>// GREETING_MESSAGE为字符串常量,将被存储在只读数据段
//"Hello, world!"为字符串常量,将被存储在只读数据段
const char* const GREETING_MESSAGE = "Hello, world!";// DAYS_IN_WEEK为只读的全局常量,也会被放置在只读数据段
const int DAYS_IN_WEEK = 7;int main() {// 打印存储在只读数据段的字符串常量std::cout << GREETING_MESSAGE << std::endl;// 打印存储在只读数据段的全局常量std::cout << "There are " << DAYS_IN_WEEK << " days in a week." << std::endl;return 0;
}

3.读写初始化数据段

存储内容

存储在程序编译时已经初始化的全局变量。
静态变量(C++类的静态成员变量,函数的静态变量)。

生命周期

开始:程序开始执行时。
结束:程序执行结束后由操作系统回收。

初始化时机

全局变量:在程序启动时,main函数执行之前。
类的静态成员变量:在程序启动时,main函数执行之前。
函数内的静态变量:只会在第一次调用函数时初始化。

特点

这些变量可以在程序运行时被修改。

代码演示

#include <iostream>// 全局变量,已初始化,会被存储在读写初始化数据段
int globalCounter = 0;// 类的静态成员变量,也存储在读写初始化数据段
class Example {
public:static int staticMember;
};
int Example::staticMember = 1;void incrementCounter() {// 函数内的静态变量,只会在第一次调用函数时初始化,存储在读写初始化数据段static int counter = 0;counter++;std::cout << "Counter: " << counter << std::endl;
}int main() {// 打印全局变量和静态成员变量的初始值std::cout << "Global counter: " << globalCounter << std::endl;std::cout << "Static member: " << Example::staticMember << std::endl;// 修改全局变量和静态成员变量的值globalCounter++;Example::staticMember++;// 打印修改后的值std::cout << "Global counter: " << globalCounter << std::endl;std::cout << "Static member: " << Example::staticMember << std::endl;return 0;
}

4. 堆区(Heap)

存储内容

动态内存分配的对象。

生命周期

开始:通过动态内存分配函数(如C++中的 new 或C中的 malloc )创建。
结束:通过对应的内存释放函数(如C++中的 delete 或C中的 free )显式释放。

初始化时机

初始化时机取决于具体的分配和初始化方式。
使用new操作符的时候,可以同时进行分配和初始化。
使用malloc等C语言风格的内存分配时,分配和初始化是分开的,初始化需要显式进行。

特点

堆向高地址增长(即“向上”增长)。

代码演示

#include <iostream>class Sample {
public:int value;Sample(int v) : value(v) {}  // 构造函数void display() { std::cout << "Value: " << value << std::endl; }
};int main() {// 在堆上动态分配一个Sample对象Sample* samplePtr = new Sample(10);  // 分配并初始化// 使用对象samplePtr->display();  // 显示 "Value: 10"// 释放分配的内存delete samplePtr;  // 结束对象的生命周期return 0;
}

5. 栈区(Stack)

存储内容

局部变量。
函数参数。
返回地址。
控制流信息等。

生命周期

开始:当声明一个局部变量或进入一个函数时。
结束:当离开变量的作用域或函数返回时。

初始化时机

局部变量在声明时可以进行初始化。
函数参数在函数调用时,通过传递实参来初始化。

特点

栈通常向低地址增长(即“向下”增长)。

代码演示

#include <iostream>void function() {int localVar = 5; // 局部变量的声明和初始化std::cout << "Local variable in function: " << localVar << std::endl;// 离开函数时,localVar的生命周期结束
}int main() {function(); // 调用function,localVar在这里开始生命周期// 在这里,function中的localVar不再存在,已经被自动销毁return 0;
}

6.命令行参数

存储内容

argc(Argument Count): 一个整数,表示传递给程序的命令行参数数量,包括程序名本身。

argv(Argument Vector): 一个字符串数组,存储具体的参数值。argv[0]是程序名,argv[1]至argv[argc-1]是用户传递给程序的参数。

生命周期

开始:程序启动时,操作系统准备命令行参数。
结束:程序终止时,命令行参数的生命周期结束。

初始化时机

命令行参数在程序启动之前由操作系统解析和准备,然后在程序的main函数启动时通过argc和argv参数传递给程序。

特点

命令行参数是在程序启动时由操作系统传递给程序的参数,这些参数允许用户指定程序运行时的行为或输入。在C和C++中,这些参数通过main函数的参数接收,通常是两个参数:argc(参数计数)和argv(参数向量)。

代码演示

#include <iostream>int main(int argc, char *argv[]) {std::cout << "You have entered " << argc << " arguments:" << std::endl;for(int i = 0; i < argc; ++i) {std::cout << argv[i] << std::endl;}return 0;
}

这个程序会输出用户输入的所有命令行参数,包括程序名本身。假设程序名为program,并且运行时输入了两个额外的参数arg1 arg2,那么输出将会是:

You have entered 3 arguments:
program
arg1
arg2

7.环境变量

存储内容

键值对形式的字符串,其中键是变量名,值是设置的值。

生命周期

开始:在计算机启动或用户登录时由操作系统初始化。
结束:在计算机关闭或用户登出时结束。

初始化时机

环境变量在程序启动前由操作系统初始化,对所有的程序和进程都是可见的。

特点

环境变量是操作系统中用于存储系统级或用户级配置信息的全局变量。它们由操作系统或用户设置,并在程序启动前就已经存在。

代码演示

#include <iostream>
#include <cstdlib> // 提供getenvint main() {// 获取名为"PATH"的环境变量const char* path = getenv("PATH");if (path != nullptr) {std::cout << "PATH: " << path << std::endl;} else {std::cout << "PATH environment variable does not exist." << std::endl;}return 0;
}

这段代码中,getenv函数尝试获取名为"PATH"的环境变量的值。如果该环境变量存在,它会返回指向相应值的指针;如果不存在,返回nullptr。

环境变量对程序是只读的;尽管程序可以修改自己的环境变量副本,但这些修改不会影响到其他程序或操作系统级别的设置。

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

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

相关文章

相交链表:寻找链表的公共节点

目录 一、公共节点 二、题目 三、思路 四、代码 五、代码解析 1.计算长度 2.等长处理 3.判断 六、注意点 1.leetcode的尿性 2.仔细观察样例 3.经验总结 一、公共节点 链表不会像两直线相交一样&#xff0c;相交之后再分开。 由于单链表只有一个next指针&#xff0…

Linux:Jenkins全自动持续集成持续部署(3)

在上一章部署好了之后&#xff0c;还需要点击一下才能进行部署&#xff0c;本章的效果是&#xff1a;当gitlab上的代码发生了变化后&#xff0c;我们不需要做任何事情不需要去点击构建按钮&#xff0c;Jenkins直接自动检测变化&#xff0c;然后自动去集成部署Linux&#xff1a;…

Dr4g0n

信息收集 # nmap -sn 192.168.56.0/24 -oN live.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2024-03-04 08:52 CST Nmap scan report for 192.168.56.2 Host is up (0.00012s latency). MAC Address: 00:50:56:FE:B1:6F (VMware) Nmap scan report …

MATLAB下载+安装教程

下载 MATLAB&#xff1a; 访问 MathWorks 官方网站&#xff1a;MathWorks 官方网站在网站上找到 "Downloads"&#xff08;下载&#xff09;选项&#xff0c;并选择 MATLAB。登录或创建一个 MathWorks 帐号。选择您希望下载的 MATLAB 版本&#xff0c;并根据您的操作…

二进制源码部署mysql8.0.35

二进制部署mysql8.0.35 创建mysql用户 [rootzyq ~]#: useradd -r -s /sbin/nologin -M mysql [rootzyq ~]#: id mysql uid990(mysql) gid990(mysql) groups990(mysql)上传mysql文件 [rootzyq ~]#: ls anaconda-ks.cfg mysql-8.0.35-linux-glibc2.28-x86_64.tar.xz解压 [roo…

Uniapp manifest

manifest.json 应用配置 manifest.json 文件是应用的配置文件&#xff0c;用于指定应用的名称、图标、权限等。HBuilderX 创建的工程此文件在根目录&#xff0c;CLI 创建的工程此文件在 src 目录。 #配置项列表 属性类型默认值描述最低版本nameString应用名称appidString新建…

飞鸟写作靠谱吗 #知识分享#媒体

飞鸟写作是一个被广泛使用的论文写作工具&#xff0c;它不仅可以帮助用户快速完成论文写作&#xff0c;还可以进行查重和降重&#xff0c;确保论文的原创性。那么&#xff0c;飞鸟写作到底靠不靠谱呢&#xff1f;在我看来&#xff0c;飞鸟写作绝对是一个靠谱的工具。 首先&…

hadoop基本概念

一、概念 Hadoop 是一个开源的分布式计算和存储框架。 Hadoop 使用 Java 开发&#xff0c;所以可以在多种不同硬件平台的计算机上部署和使用。其核心部件包括分布式文件系统 (Hadoop DFS&#xff0c;HDFS) 和 MapReduce。 二、HDFS 命名节点 (NameNode) 命名节点 (NameNod…

【ai技术】(4):在树莓派上,使用qwen0.5b大模型+chatgptweb,搭建本地大模型聊天环境,速度飞快,非常不错!

1&#xff0c;视频地址 https://www.bilibili.com/video/BV1VK421i7CZ/ 2&#xff0c;下载镜像 raspberry-pi-os-64-bit https://blog.csdn.net/freewebsys/article/details/136921703 项目地址&#xff1a; https://www.raspberrypi.com/software/operating-systems/#rasp…

【数据挖掘】实验5:数据预处理(1)

实验5&#xff1a;数据预处理&#xff08;1&#xff09; 一&#xff1a;实验目的与要求 1&#xff1a;熟悉和掌握数据预处理&#xff0c;学习数据清洗、数据集成、数据变换、数据规约、R语言中主要数据预处理函数。 二&#xff1a;实验内容 【缺失值分析】 第一步&#xff1…

jmeter使用方法---自动化测试

HTTP信息头管理器 一个http请求会发送请求到服务器&#xff0c;请求里面包含&#xff1a;请求头、请求正文、请求体&#xff0c;请求头就是信息头Authorization头的主要用作http协议的认证。 Authorization的作用是当客户端访问受口令保护时&#xff0c;服务器端会发送401状态…

C语言UDP基础CS模型

CS模型UDP流程: 服务器: socket->bind->recvfrom->sendto->close 客户端: socket->sendto->recvfrom->close 代码说明: 1 未使用更先进的服务器模型,用基础单线程阻塞(recvfrom)作为演示 2 服务器使用while循环接收客户端消息 3 适用于同一网段的不…

使用 Flink + Faker Connector 生成测试数据压测 MySQL

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

day06vue2学习

day06 路由的封装抽离 问题&#xff1a;所有的路由配置都堆在main.js中不太合适么&#xff1f;不好&#xff0c;会加大代码的复杂度 目标&#xff1a;将路由模块抽离出来。好处&#xff1a;差分模块&#xff0c;利于维护。 大致的做法就是&#xff0c;将路由相关的东西都提…

Python界面库Flet(1)介绍和快速使用

Python界面库Flet(1)快速上手使用 Author&#xff1a;Once Day Date&#xff1a;2024年3月19日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Pyt…

【QT+QGIS跨平台编译】之九十:【QGIS_Crashhandler+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、QGIS_Crashhandler介绍二、QGIS下载三、文件分析四、pro文件五、编译实践一、QGIS_Crashhandler介绍 QGIS_Crashhandler模块是QGIS中的一个重要组成部分,它提供了QGIS程序的错误崩溃处理与跟踪。 二、QGIS下载 QGIS网址: QGIS Source Download 获取最新版本的…

RabbitMq高可用

消息队列高级 服务异步通信-高级篇1.消息可靠性1.1.生产者消息确认1.2.消息持久化1.3.消费者消息确认1.4.消费失败重试机制1.5.总结 2.死信交换机2.1.初识死信交换机2.2.TTL2.3.延迟队列 3.惰性队列3.1.消息堆积问题3.2.惰性队列 4.MQ集群4.1.集群分类4.2.普通集群4.3.镜像集群…

Linux shell脚本切换为root用户执行命令

首先安装expect。 sudo apt install expect 创建shell脚本文件&#xff0c;示例内容如下&#xff1a; #!/usr/bin/expectspawn su rootexpect {"密码&#xff1a;" {send "00000\r"}"Password:" {send "000000\r"}}send "./…

【物联网开源平台】tingsboard二次开发环境搭建+编译

文章目录 一&#xff0c;需要准备的环境二&#xff0c;获取tingsboard源码1.git拉取源码2.下载源码压缩包 三.新建仓库存放依赖文件四&#xff0c;编译五&#xff0c;遇到的错误 提示&#xff1a; 1.这篇只要准备两个环境&#xff0c;方法更简单&#xff01; 2.基于tingsboard …

网盘——客户端服务器搭建

1、配置文件加载 资源文件 将服务器IP和PORT信息填入配置文件中 将配置文件作为资源文件添加到资源文件中 程序运行时加载配置文件中的数据 1.1、首先在创建好的代码目录下面创建一个配置文件 代码目录怎么找到的呢&#xff1f; 1.2、在这个路径下面&#xff0c;创建一个…