Linux系统下C++程序运行时的内存布局及存储内容,生命周期,初始化时机。【C++】

Linux系统下C++程序运行时的内存布局及存储内容,生命周期,初始化时机详解。

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

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

1.程序代码段

存储内容

存储CPU能够执行的程序的机器指令。包括程序的自定义函数和库函数(包括静态库和动态库)编译后的机器代码。

静态库:编译时整合到可执行文件。

动态库(Linux 下的 .so 文件,Windwos 下的 .dll 文件):程序运行时被加载到内存。

生命周期

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

初始化时机

不涉及。

特点

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

代码演示

不涉及。

2.初始化数据段 - 只读初始化数据段

存储内容

编译时初始化且运行时不需要修改的数据。
const char * 指针的指向。
const char* const 指针的指向和指针的地址。
const 修饰的全局变量。
const 修饰的命名空间作用域内的变量。

生命周期

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

初始化时机

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

特点

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

代码演示

代码演示:

#include <iostream>

// GREETING_MESSAGE为只读的全局字符串常量,被放置在只读初始化数据段
const char* const GREETING_MESSAGE = "Hello, world!";

// DAYS_IN_WEEK为只读的全局int常量,被放置在只读初始化数据段
const int DAYS_IN_WEEK = 7;

// someConstant为只读的命名空间 someConstant 的int常量,被放置在只读初始化数据段
namespace MyNamespace
{
   const int someConstant = 42;
}

int main() {
    // 打印存储在全局命名空间的只读数据段的字符串常量
    std::cout << GREETING_MESSAGE << std::endl;

    // 打印存储在全局命名空间的只读数据段的整型常量
    std::cout << "There are " << DAYS_IN_WEEK << " days in a week." << std::endl;

    // 打印存储在命名空间 MyNamespace 的只读数据段整型常量
    std::cout << MyNamespace::someConstant << std::endl;

    return 0;
}

运行结果:
运行结果

3.初始化数据段 - 读写初始化数据段

存储内容

编译时初始化且运行时可以修改的数据。
全局变量。
类的静态成员变量。
函数内的静态变量。

生命周期

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

初始化时机

全局变量:在程序启动时,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;

    incrementCounter();

    return 0;
}

运行结果:
运行结果

4.未初始化数据段 .bss段

存储内容

未初始化的全局变量。
未初始化的静态变量。

生命周期

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

初始化时机

程序的启动阶段,特别是在main函数执行之前,运行时环境会将未初始化数据段中的所有内存区域自动初始化为零或空(对于指针变量)。

特点

代码演示

#include <iostream>

// 全局变量,未初始化,默认存储在.bss段
static int global_uninit_var;

// 静态全局变量,未初始化,默认也存储在.bss段
static int static_uninit_var;

int main() 
{
    // 局部静态变量,未初始化,存储在.bss段
    static int static_local_uninit_var;

    // 打印变量的值,预期输出都为0
    std::cout << "global_uninit_var:" << global_uninit_var << std::endl;
    std::cout << "static_uninit_var:" << static_uninit_var << std::endl;
    std::cout << "static_local_uninit_var:" << static_local_uninit_var << std::endl;
    return 0;
}

运行结果:
运行结果

在上面的代码中:

global_uninit_var 是一个全局变量,它没有被显式初始化,所以默认值是0。
static_uninit_var 是一个静态全局变量,同样没有被初始化,其默认值也是0。
static_local_uninit_var 是一个静态局部变量,在函数内部声明,没有被初始化,因此它也将被存储在.bss段,并且其默认值是0。

当你编译并运行这个程序时,这些变量都会被置为0。这是因为它们都是在.bss段中并且在程序启动阶段被自动清零。这种行为确保了未初始化的静态和全局变量有一个确定的起始值。

5.常量数据段

存储内容

程序中的常量。

生命周期

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

初始化时机

在程序加载到内存并开始运行之前,由操作系统完成的。

特点

代码演示

#include <iostream>

int main() {
    // Hello, World! 字符串字面量存储在常量数据段中
    const char* hello = "Hello, World!";
    
    // 打印存储在常量数据段的字符串
    std::cout << hello << std::endl;
    
    return 0;
}

运行结果:
运行结果

6. 堆区(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;
}

运行结果:
运行结果

7. 栈区(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;
}

运行结果:
运行结果

8.命令行参数

存储内容

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

9.环境变量

存储内容

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

生命周期

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

初始化时机

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

特点

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

代码演示

#include <iostream>
#include <cstdlib> // 提供getenv

int 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。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

aws使用记录

数据传输&#xff08;S3) 安装命令行 安装awscli: https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions 直到 aws configure list 可以运行 身份验证&#xff1a; 运行&#xff1a; aws config…

35岁的程序员,该何去何从?

2024 年&#xff0c;是充满未知和挑战的一年。AI 的发展日新月异&#xff0c;已经有人用它来写代码了&#xff0c;啥时候会替代程序员&#xff0c;可真不好说。另一方面&#xff0c;程序员扎堆的 IT 互联网行业却进入了平台期甚至下行期&#xff0c;降本增效成为行业主流&#…

SAP_MMQM模块-采购收货质量控制

采购订单收货如何控制质量检验后再放行使用&#xff0c;针对目前了解到的功能&#xff0c;有以下三种方案&#xff1b; 一、启用QM模块&#xff0c;正常使用MIGO收货-移动类型101&#xff0c;入库后产生检验批&#xff0c;产生质检库存&#xff0c;质检部检验合格后&#xff0…

Vue2(十一):脚手架配置代理、github案例、插槽

一、脚手架配置代理 1.回顾常用的ajax发送方式&#xff1a; &#xff08;1&#xff09;xhr 比较麻烦&#xff0c;不常用 &#xff08;2&#xff09;jQuery 核心是封装dom操作&#xff0c;所以也不常用 &#xff08;3&#xff09;axios 优势&#xff1a;体积小、是promis…

Unbtun-arach64架构安装PySide2(python3.6)

aarch平台是无法通过pip安装PySide2的&#xff0c;同时利用源码下载一直报错 1. 我是python3.6.9&#xff0c;在官网上找到对应的PySide2版本 5.15.2.所以首先在官网下载Qt5.15.2的源码&#xff1a;https://download.qt.io/archive/qt/5.15/5.15.2/single/ 2. 编译qt环境 aar…

C++基础11:模板与命名空间

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C从入门到深入的专栏&#xff0c;参考书籍&#xff1a;《深入浅出 C {\rm C} C》(马晓锐)和《从 C {\rm C} C到 C {\rm C} C精通面向对象编程》(曾凡锋等)。 10.模板与命名空间 10.1 模板简述 模板使函数和类的处理对象…

RecyclerView notifyItemChanged 之后的源码分析

注意&#xff1a;本文是基于 androidx.RecyclerView 1.3.2 版本的源码分析。默认使用 DefaultItemAnimator&#xff0c;如果使用了其他的 ItemAnimator&#xff0c;可能会有不同的表现。 效果图&#xff1a; 示例代码如下&#xff1a; binding.btnNotifyItemChanged.setOnCli…

openstack 不能调度到某主机上分析

dashboard显示有足够资源创建虚拟机 创建一个1c2g20g配置的虚拟机&#xff0c;在过滤时把10-197-0-2这个主机过滤掉了&#xff0c;日志如下&#xff1a; 2024-03-25 17:52:14.087 26 DEBUG nova.scheduler.filters.disk_filter [req-8f2f32fb-1efe-4e5d-81fc-618210c7c76d 773…

TorchAcc:基于 TorchXLA 的分布式训练框架

演讲人&#xff1a;林伟&#xff0c;阿里云研究员&#xff0c;阿里云人工智能平台 PAI 技术负责人 本文旨在探讨阿里云 TorchAcc&#xff0c;这是一个基于 PyTorch/XLA 的大模型分布式训练框架。 过去十年 AI 领域的显著进步&#xff0c;关键在于训练技术的革新和模型规模的快…

【XXL-JOB】执行器架构设计和源码解析

简介 XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。 XXL-JOB分为B/S架构&#xff0c;调用中心是XXL-JOB服务端&#xff0c;执行器是客户端。 调度中心核…

【1】网络协议基础概念

【1】网络协议基础知识 1、互联网2、为什么要学习网络协议3、学习中需要搭建的环境4、客户端-服务器5、Java 的跨平台原理6、C/C的跨平台原理7、一个简单的SpringBoot项目(1) pom.xml(2) application.yml(3) NetworkStudyApp.java(4) SwaggerConfig.java(5) HelloWorldControll…

CXL系统架构

CXL系统架构 CXL支持三种设备类型&#xff0c;如下图。Type 1支持CXL.cache和CXL.io&#xff1b;Type 2支持CXL.cache&#xff0c;CXL.mem和CXL.io&#xff1b;Type 3支持CXL.mem和CXL.io。无论哪种类型&#xff0c;CXL.io都是不可缺少的&#xff0c;因为设备的发现&#xff0…

Deconstructing Denoising Diffusion Models for Self-Supervised Learning解读(超详细)

论文题目&#xff1a;Deconstructing Denoising Diffusion Models for Self-Supervised Learning 原文链接&#xff1a;https://arxiv.org/html/2401.14404v1 本文是对何凯明老师的新作进行的详细解读&#xff0c;其中穿插了一些思考&#xff0c;将从以下四个方面对这篇工作进…

3723. 字符串查询:做题笔记

目录 思路 代码 注意点 3723. 字符串查询 思路 这道题感觉和常见的前缀和问题不太一样&#xff0c;前缀和的另一种应用&#xff1a;可以统计次数。 这道题我们想判断一个单词的其中一段子序列A是否可以通过重新排列得到另一段子序列B。 我看到这道题的时候想着可能要判…

Gitlab 实现仓库完全迁移,包括所有提交记录、分支、标签

1 方案一&#xff1a;命令 cd <项目目录> git fetch --all git fetch --tags git remote rename origin old-origin #可以不保留 git remote add origin http://***(项目的新仓库地址) #git remote set-url origin <项目的新仓库地址> git push origin --all git…

Qt 多线程QThread的四种形式

重点&#xff1a; 1.互斥量&#xff1a;QMutex配套使用&#xff0c;lock(),unlock(),如果一个线程准备读取另一个线程数据时候采用tryLock()去锁定互斥量&#xff0c;保证数据完整性。 QMutexLocker简化版的QMutex,在范围区域内使用。 QMutex mutex QMutexLocker locker(&…

达梦数据库新手上路排坑

数据库安装 这个没啥说的&#xff0c;按照官网教程操作&#xff0c;我使用的是docker进行安装 下载文件docker文件 官方下载地址- load -i dm8****.tar (注意修改为当前下载的文件)达梦官方文档注意修改为当前版本 docker run -d -p 5236:5236 --name dm8 --privilegedtrue -…

程序员口才提升技巧:从技术到沟通的进阶之路

程序员口才提升技巧&#xff1a;从技术到沟通的进阶之路 在数字化时代&#xff0c;程序员作为推动技术发展的关键角色&#xff0c;其专业能力的重要性不言而喻。然而&#xff0c;除了编程技能外&#xff0c;良好的口才同样是程序员职业生涯中不可或缺的一部分。本文将探讨程序…

学透Spring Boot — [二] Spring 和 Spring Boot的比较

欢迎关注我们的专栏 学透 Spring Boot 一、创建一个简单Web应用 本篇文章&#xff0c;我们将会比较 Spring 框架和 Spring Boot 的区别。 什么是 Spring? 也许你在项目中已经可以很熟练的使用 Spring 了&#xff0c;但是当被问到这个问题时&#xff0c;会不会犹豫一下&#…

2024-3-28 市场情绪强修复

这一轮退潮负反馈都修复了&#xff0c; 艾艾精工 博信股份 安奈尔 永悦科技 大理药业 &#xff0c;高新发展 也补跌了&#xff0c;收尸队也干活了&#xff0c;情绪不修复不接力得最好写照。这轮周期 宁科生物 已经7板&#xff0c;已经追平了 博信股份7板&#xff0c;看明天溢…