linux-环境变量,进程地址空间

news2024/9/22 17:33:14

1.环境变量

1.1基本概念

环境变量 (environment variables) 一般是指在操作系统中用来指定操作系统运行环境的一些参数
如:我们在编写 C/C++ 代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但 是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

下面这段代码就是将命令行参数传递给main函数的参数,然后进行模仿命令行的指令+选项,选项的本质也就是命令行参数。

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cout << "Usage: " << argv[0] << "-number[1-3]" << endl;
        return -1;
    }
    if (strcmp("-1", argv[1]) == 0)
        cout << "Function 1" << endl;
    else if (strcmp("-2", argv[1]) == 0)
        cout << "Function 2" << endl;
    else if (strcmp("-3", argv[1]) == 0)
        cout << "Function 3" << endl;
    else if (strcmp("-4", argv[1]) == 0)
        cout << "Function 4" << endl;
    else if (strcmp("-5", argv[1]) == 0)
        cout << "Function 5" << endl;
    else
        cout<<"unknown!"<<endl;
    return 0;
}

1.2查看环境变量方法

echo $NAME //NAME: 你的环境变量名称

1.3常见环境变量

PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录 ( 即用户登陆到 Linux 系统中时 , 默认的目录 )
SHELL : 当前 Shell, 它的值通常是 /bin/bash

这个全局的环境变量就是能够查看到指定命令的搜索路径,也就是说这个搜索路径是os的默认搜索路径,所以我们执行自己写的程序时,需要加./来告诉os我们的程序是在当前目录下,当然我们也可以修改PATH。

 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)

1.4环境变量相关的命令

1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的 shell 变量和环境变量

1.5通过代码如何获取环境变量 

命令行第三个参数
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
 int i = 0;
 for(; env[i]; i++){
 printf("%s\n", env[i]);
 }
 return 0;
}

1.6环境变量通常是具有全局属性的

int main(int argc, char *argv[], char *env[])
{
    cout << "I am process, pid: " << getpid() << ", ppid: " << getppid() << endl;
    for (int i = 0; env[i]; i++)
    {
        printf("---------env[%d] -> %s\n", i, env[i]);
    }
    pid_t id = fork();
    if (id == 0)
    {
        cout<<"----------------------------------------"<<endl;
        cout << "I am child, pid: " << getpid() << ", ppid: " << getppid() << endl;
        for (int i = 0; env[i]; i++)
        {
            printf("---------env[%d] -> %s\n", i, env[i]);
        }
    }
    return 0;
}

 通过上面这段代码已经结果可以发现环境变量是会被子进程继承下去的,再一次验证了环境变量具有全局属性,可以被所有子进程继承下去。

1.7通过系统调用获取或设置环境变量

getenv()这个函数就能够获取到环境变量,这是一个系统调用的接口。

int main()
{
    const char* username=getenv("USER");
    if(username) 
        cout<<"USER: "<<username<<endl;
    else
        cout<<"NONE"<<endl;
    return 0;
}


2.地址空间

2.1地址空间分布

我们可以使用下面这段代码来验证一下地址空间的分布是否如上图所示。

int g_unval;
int g_val = 100;

int main(int argc, char *argv[], char *env[])
{
   printf("code addr: %p\n", main);
   printf("init data addr: %p\n", &g_val);
   printf("uninit data addr: %p\n", &g_unval);

   char *heap = (char*)malloc(20);
   char *heap1 = (char*)malloc(20);
   char *heap2 = (char*)malloc(20);
   char *heap3 = (char*)malloc(20);
   static int c;
   printf("heap addr: %p\n", heap);
   printf("heap1 addr: %p\n", heap1);
   printf("heap2 addr: %p\n", heap2);
   printf("heap3 addr: %p\n", heap3);

   printf("stack addr: %p\n", &heap);
   printf("stack addr: %p\n", &heap1);
   printf("stack addr: %p\n", &heap2);
   printf("stack addr: %p\n", &heap3);
   printf("c addr: %p, c: %d\n", &c, c);
}

可以发现地址空间的分布确实是如上图所示。

2.2进程地址空间

通过下面这段代码我们可以发现一个问题,就是在子进程改掉全局变量g_val之后,子进程和父进程的g_val发生了变化,这是正常的,因为进程间具有独立性,但是地址确是一样的,那么同一个地址可能存储两个不一样的值吗?这是不可能的,所以这个地址是虚拟地址


int g_val = 100;

int main()
{
    pid_t id = fork();
    if (id == 0)
    {
        int cnt=0;
        while (true)
        {
            printf("I am child, g_val: %d, &g_val: %p\n", g_val, &g_val);
            sleep(1);
            cnt++;
            if(cnt==5)
            {
                g_val=200;
                printf("child change g_val:100->200\n");
            }
        }
    }
    else
    {
        while (true)
        {
            printf("I am father, g_val: %d, &g_val: %p\n", g_val, &g_val);
            sleep(1);
        }
    }
    return 0;
}

虚拟地址没有保存数据的能力,所以数据都存放在物理内存,因此需要通过虚拟内存的地址找到对应的物理内存的地址,所以os会维护一张页表,这张页表有着映射关系,也就是虚拟地址到物理地址的映射,类似于数组的下标与数据的关系。

那么每一个进程运行之后都有自己的进程地址空间,并且在os层面都要有页表映射结构,那么子进程在创建出来后会继承父进程的大部分数据,当然包括这张页表,所以我们在上面的测试中能够看到g_val这个变量在子进程和父进程的地址是一样的,因为连映射关系都是一样的。

 那么当子进程修改了这个变量时,因为进程具有独立性,为了不影响到父进程,在修改之前os会在物理内存中开辟一段新的空间,将原数据拷贝一份到这个新的空间,这个过程就叫写时拷贝,然后子进程的页表映射关系也发生改变,所以我们能看到g_val这个变量在子进程和父进程的地址是一样的,因为是虚拟内存,但是值却不一样,因为通过页表映射的物理地址不一样。

2.3为什么要有进程地址空间

2.3.1无序到有序

一个程序要放到物理内存当中,那么是可以放在任意位置的,那么就可以通过页表让我们以更有序的视角看到虚拟内存,也就是让进程以统一的视角看待内存,所以任意一个进程,可以通过地址空间+页表将乱序的内存数据,变成有序。

2.3.2安全检查

其实页表旁边还有一个字段叫做访问权限字段,代表着这个虚拟地址到物理地址的访问权限,也就是r和w,在进行越界访问和修改数据时会进行拦截,比如:字符常量不可被修改,就是因为内存被设置了只读权限。这样就可以有效地进行地址访问内存时的安全检查

 2.3.4如何找到进程相应的页表

系统中有那么多的页表,那么如何找到这个进程所对应的页表呢?通过寄存器CR3就能找到这个页表的地址,然后通过页表的映射来找到物理地址,那么有一个小问题,那么这个页表的地址是虚拟地址还是物理地址呢?这个地址其实是物理地址,因为虚拟地址是为了给用户来使用的,而这个CR3是系统内部的,没必要用虚拟地址。

2.3.5 进程切换

当一个进程在cpu上运行的时候,CR3里面的内容本质是在该进程的进程上下文当中,也就是说页表的地址是在进程上下文中,那么当切换数据的时候,也要把数据的页表地址保存到进程的上下文中,所以每一个进程都要有自己独立的页表地址的起始数据。所以当进程切换时,要把PCB和进程的页表地址都要进行切换。那么进程的地址空间是在PCB中的,只需要切换PCB,就可以把页表,地址空间,数据全部切换了。

2.3.6 进程挂起

进程挂起在linux中的体现就是当进程正在运行,系统内存已经严重不足,这个进程代码和内存依旧要占空间,但是又不会被调度,那么OS就会把这个进程挂起,那么我们怎么知道这个进程挂起了呢?其实在页表中还有一个字段用来表明这个进程的物理地址是否在内存当中,并且是否有内容。

 通过二进制来标记是否分配和是否有内容,如果都为0的话表示没有分配内存并且没有内容,表示这个进程被OS挂起了。

2.3.7 缺页中断

当OS需要访问一个虚拟地址为0x112233的程序时,通过页表查看到标记为是00,代表没有分配内存,并且没有内容,此时OS会强制暂停这次访问,等待在内存中重新开辟空间,将物理地址放入映射,然后修改标记位。那么这个过程就叫做缺页中断。

 那么进程切换,进程挂起,缺页中断这些事情进程都是不知道的,都是内存管理,也就是进程地址空间在执行,这样就实现了OS层面上模块的解耦,也就是为什么要有进程地址空间和页表的理由。


今天的分享到这里就结束啦,感谢大家的阅读!

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

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

相关文章

Stable Diffusion绘画 | 文生图设置详解—随机种子数(Seed)

随机种子数&#xff08;Seed&#xff09; Midjourney 也有同样的概念&#xff0c;通过 --seed 种子数值 来使用。 每次操作「生成」所得到的图片&#xff0c;都会随机分配一个 seed值&#xff0c;数值不同&#xff0c;生成的画面就会不同。 默认值为 -1&#xff1a;每次随机分…

速度规划之:起点速度和终点速度不为零的非对称梯形速度规划

起点速度和终点速度不为零的非对称梯形速度规划 一、引言二、理论基础1. 梯形速度规划概述2.数学建模- 变量定义- 约束关系- 公式推导 三、计算过程1.只存在减速段2.只存在加速段3.存在加速段和减速段4.存在加速度段、匀速段和减速段 四、仿真实现五、优缺点优点缺点 六、总结 …

电销外呼系统是如何实现高效触客?

首先我们都有个疑问&#xff1f; 什么是外呼系统&#xff0c;有什么用处 简单来说就是解决打电话高频封号问题&#xff0c;提升销售工作效率&#xff0c;搞笑筛选一线客户 沃创云电销外呼系统通过一系列智能化、自动化的功能和技术手段&#xff0c;实现了高效触客。以下是该系…

MySQL数据库学习笔记

1、数据库的相关概念 数据库是存储数据的仓库,数据是有组织的进行存储 (DataBase)DB. 数据库管理系统:操作和管理数据库的大型软件 DataBase Mangement System(DBMS) SQL 操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准。 1、Oracle 2、MySQL 3…

LLC数字控制TMS320F28034,3-DSP的timer定时器配置介绍

***配套代码工程*** LLC数字控制TMS320F28034&#xff0c;3-DSP的timer定时器配置介绍 LLC数字控制TMS320F28034&#xff0c;3-DSP的timer定时器配置介绍1 TMS320F280341.1 系统时钟大小1.2 TMS320F28034 芯片系统时钟源介绍 2 时钟库函数说明示例3 TMS320F28034手写定时器功能…

武汉流星汇聚:亚马逊平台消费者众多,助力中国卖家销售额大幅增长

在全球电商的浩瀚星空中&#xff0c;亚马逊凭借其庞大的消费者规模和强大的市场影响力&#xff0c;为无数商家特别是中国卖家提供了前所未有的发展机遇。近年来&#xff0c;越来越多的中国卖家选择通过亚马逊平台&#xff0c;将优质产品直接送达全球消费者的手中&#xff0c;并…

【系统架构设计师】二十三、通信系统架构设计理论与实践②

目录 二、5G 网络边缘计算 三、存储网络架构 四、软件定义网络架构 五、网络构建关键技术 5.1 网络的高可用性 5.2 IPv4 与 IPv6 融合组网技术 六、网络构建和设计方法 6.1 网络需求分析 6.2 网络技术遴选及设计 6.3 层次化网络模型设计 6.4 网络安全控制技术 6.5 …

基于Gromacs的蛋白质与小分子配体相互作用模拟教程

在生命科学的广阔领域中&#xff0c;蛋白质与小分子配体之间的相互作用扮演着至关重要的角色。这些相互作用不仅影响着生物体内的各种生命活动&#xff0c;如信号传导、代谢调控和药物作用等&#xff0c;同时也是药物设计和开发的核心内容。因此&#xff0c;深入理解并模拟这些…

模板进阶【C++】

文章目录 模板的特殊化函数模板特化的作用 函数模板的的特殊化语法&#xff1a;函数模板特化的要求 类模板的特殊化类模板的特殊化的要求类模板的特殊化的语法全特化偏特化实例化部分模板参数对基本类模板&#xff08;母板&#xff09;的模板参数进行限制 非类型模板参数非类型…

ESP32低功耗蓝牙服务端的库介绍和实例演示

ESP32低功耗蓝牙服务端的库介绍和实例演示 1.概述 前面的文章介绍了经典蓝牙库和使用示例&#xff0c;这篇文章介绍低功耗蓝牙库的使用。 这篇文章不介绍低功耗蓝牙实现的架构知识&#xff0c;只介绍 如何使用它的库文件实现应用开发只介绍服务端蓝牙开发方式 2.低功耗蓝牙…

R语言大尺度空间数据分析模拟预测及可视化:地统计与空间自相关、空间数据插值、机器学习空间预测、空间升降尺度、空间模拟残差订正、空间制图等

目录 专题一 R语言空间数据介绍及数据挖掘关键技术 专题二 R语言空间数据高级处理技术 专题三 R语言多维时空数据处理技术、数据清洗整合和时间序列分析 专题四 R语言地统计与空间自相关、空间插值方法 专题五 R语言机器学习与空间模型预测及不确定性评估 专题六 R语言空…

htsjdk库ReferenceSequenceFile接口介绍

ReferenceSequenceFile 是 HTSJDK 库中的一个接口,用于表示参考基因组文件。它定义了读取参考基因组序列的标准方法。这个接口使得不同类型的参考基因组文件(如 FASTA 格式)能够以统一的方式进行访问。 ReferenceSequenceFile 接口主要功能 访问参考序列: 提供获取参考基因…

如何在 Windows/Mac/iPhone/Android 上将 PDF 转换为 Word

PDF&#xff08;便携式文档格式&#xff09;是一种流行的格式&#xff0c;广泛用于在数字电子设备中呈现文档。输出文件小且兼容性强&#xff0c;使 PDF 如此受欢迎。但是&#xff0c;编辑 PDF 文件并非免费。您无需购买 PDF 编辑器&#xff0c;而是可以将 PDF 转换为 Word 进行…

嘉兴网站建设的思路

随着互联网的快速发展&#xff0c;网站已经成为企业宣传和推广的重要工具。作为浙江省的一个重要城市&#xff0c;嘉兴具有得天独厚的地理位置和经济实力&#xff0c;因此开展嘉兴网站建设具有重要意义。在进行网站建设的过程中&#xff0c;需要有一定的思路和规划&#xff0c;…

跑深度学习模型Ⅱ:一文安装正确pytorch及dgl

如果要用到GPU &#xff0c;先看这篇安装并保证cuda可用。跑深度学习模型I&#xff1a;一文正确使用CUDA-CSDN博客 啊每次都是pytorch版本问题引发的一系列错误&#xff01; 1. 查看自己的cuda版本 nvcc --version 可以看到我的cuda版本是11.8 nvidia-smi 查看NVIDIA驱动版…

智能变“智障”?云鲸扫地机器人频发故障引质疑

近年来&#xff0c;扫地机器人市场以其智能化技术革新和不断升级的产品功能&#xff0c;成功吸引了消费者的目光&#xff0c;甚至打破了家电行业的价格僵局&#xff0c;实现了价格与价值的双重攀升。然而&#xff0c;在这股智能家电的浪潮中&#xff0c;云鲸扫地机器人却因其频…

【C++从小白到大牛】栈和队列(优先级队列)

目录 引言&#xff1a; 使用方法篇&#xff1a; stack&#xff1a; queue priority_queue 使用方法&#xff1a; 模拟实现篇&#xff1a; stack&#xff1a; 原码&#xff1a; queue 原码&#xff1a; priority_queue 插入和删除数据的思想&#xff1a; 仿函数实…

TDEngine(taos) 涛思数据库-sql初识

一、基本使用 这里读者自行安装数据库&#xff1a;使用安装包立即开始 | TDengine 文档 | 涛思数据 (taosdata.com) // 下载gz文件&#xff0c;解压 tar -zxvf TDengine-server-<对应版本>-Linux-x64.tar.gz// 解压后启动 sudo ./install.sh 启动成功后&#xff0c;直…

动态规划之子数组系列问题

题型介绍 子数组系列动态规划问题长什么样 例题 力扣 53. 最大子数组和 解题步骤&#xff1a; 创建 dp 表以及确定 dp 表中所要填写位置的含义&#xff1a; 首先&#xff0c;根据写题经验&#xff0c;先确定出这道题应该使用的解题思路是 “以某一个位置为结尾进行分析”…

【编码心得】单元测试的那些事

【编码心得】单元测试的那些事 文章目录 单元测试定义&#xff1f;为什么需要单元测试&#xff1f;为重构保驾护航提高代码质量减少 bug快速定位 bug持续集成依赖单元测试团队编码规范要求大牛都写单元测试保住面子 TDD 测试驱动开发何谓 TDD&#xff1f;TDD的基本流程TDD 优缺…