【Linux操作系统】简学深悟启示录:环境变量&&进程地址

1.环境变量

1.1 什么是环境变量?

在这里插入图片描述

创建一个 mycode.cppmakefile 文件,按照如图文件进行示例演示,清楚了解什么是环境变量

众所周知,我们需要进行 make mycode 进行自动化编译,然后运行 ./mycode 这一执行文件才能进行打印如图的代码,但是为什么这个可执行文件不能像 lspwd 等命令一样直接使用,而是要加 ./ 这一前缀进行地址查找呢?

[zzh_test@hcss-ecs-6aa4 env_test]$ which pwd
/usr/bin/pwd
[zzh_test@hcss-ecs-6aa4 env_test]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/zzh_test/.local/bin:/home/zzh_test/bin

$PATH 表示指定命令的搜索路径,这是一个环境变量,打印出来发现,系统的命令确实是存在于这里面,这就说明了,能够直接使用而不需要类似 ./ 这样指定地址,是因为在系统里用环境变量提前定义好了路径,方便系统进行查找,因此如果执行文件想要像系统命令那样直接执行,那么就需要提前将自定义的路径加入 PATH 环境变量中,这样系统才找得到

[zzh_test@hcss-ecs-6aa4 env_test]$ pwd
/home/zzh_test/env_test
[zzh_test@hcss-ecs-6aa4 env_test]$ PATH=$PATH:/home/zzh_test/env_test
[zzh_test@hcss-ecs-6aa4 env_test]$ mycode
hello Linux10!
hello Linux9!
hello Linux8!
hello Linux7!
hello Linux6!
hello Linux5!
hello Linux4!
hello Linux3!
hello Linux2!
hello Linux1!

PATH 的修改方式是覆盖式的,因此前面要加上 $PATH:,注意 = 两侧不能有空格

在这里插入图片描述

总结: 环境变量是系统提供的一组 name=value 形式的变量,不同的环境变量有不同的用户,通常具有全局性,每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以 \0 结尾的环境字符串

1.2 查看环境变量

除了 PATH 这个环境变量,还有 HOME:指定用户的主工作目录(即用户登陆到 Linux 系统中时,默认的目录)、SHELL:当前 Shell,它的值通常是 /bin/bash 等等环境变量

[zzh_test@hcss-ecs-6aa4 ~]$ env
XDG_SESSION_ID=4167
HOSTNAME=hcss-ecs-6aa4
TERM=xterm
SHELL=/bin/bash
HISTSIZE=10000
SSH_CLIENT=113.87.225.199 59926 22
SSH_TTY=/dev/pts/0
USER=zzh_test
......

直接使用 env 命令查看就好了,具体各个环境变量的含义可以自行查询

#include <stdio.h>
#include <stdlib.h>
int main()
{
	printf("%s\n", getenv("PATH"));
	return 0;
}

也可以通过 getenv() 函数获取环境变量

1.3 命令行参数

在这里插入图片描述

查看 main 函数源代码,我们可以知道 main 函数其实是有参数的,依据这个例子理解为什么命令可以带参数

[zzh_test@hcss-ecs-6aa4 env_test]$ ./mycode
argv[0]->./mycode
[zzh_test@hcss-ecs-6aa4 env_test]$ ./mycode -a
argv[0]->./mycode
argv[1]->-a
[zzh_test@hcss-ecs-6aa4 env_test]$ ./mycode -a -b
argv[0]->./mycode
argv[1]->-a
argv[2]->-b
[zzh_test@hcss-ecs-6aa4 env_test]$ ./mycode -a -b -c
argv[0]->./mycode
argv[1]->-a
argv[2]->-b
argv[3]->-c

打印后可以发现其实命令和参数都是被存放在 char* argv[] 这个数组里的,按照顺序依次读取,这也说明了 main 函数其实也是被调用的(被 CRTStartup() 调用)

在这里插入图片描述

1.4 环境变量具有全局性

我们所运行的进程,都是子进程,bash 本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程交给我们的环境变量,因此我们在修改的 PATH 也是继承下来的,不小心删除了变量也没关系,毕竟是从系统继承下来的子进程,重启一下 bash 即可

1.5 本地变量

在这里插入图片描述
创建环境变量ENVTEST,但是只有在左边的进程能够看到,右边的进程查找不到,因为我们这里创建的是本地变量,即只能在创建的进程里被使用的环境变量,只在本 bash 内部有效,不会被子进程继承

在这里插入图片描述

解决方法也很简单,只要在前面加个 export 就能变成全局属性的环境变量了

1.6 内建命令

命令分为两种:

  • 常规命令: 通过创建子进程完成,它们并非 Shell 自身的一部分,而是操作系统预装或用户安装的独立工具,比如:lscpmv
  • 内建命令: bash 不创建子进程,而是由自己亲自执行,比如:cdecho

2.进程地址

2.1 概念引入

在这里插入图片描述

为了理解进程地址,我们将以如图所示的代码为例引入概念

在这里插入图片描述

观察输出的全局变量 g_val,发现同一个变量,同一个地址,却读取到不同的数值,这种现象很诡异?!其实是有原因的,如果变量的地址是物理地址是不可能出现上面的情况,这里的的地址是 虚拟地址(线性地址),平时写代码时写入的都是虚拟地址

2.2 进程地址空间本质

在这里插入图片描述

显而易见,父进程和子进程都各自拥有自己独立的 PCB,即 task_structPCB 里有对应的指针指向进程地址空间。依托上面的例子,对于父进程来说,这个进程地址空间是内核为进程创建的一个结构体对象,在静态区创建了 g_val,存在于进程地址空间,0x40405c 是个虚拟地址,该地址还存在于页表,然后系统会在实际存储找到空闲的物理空间供 g_val 实际存放,该物理地址也会存在于页表,与虚拟地址形成映射

对于子进程来说,它的代码数据都继承于父进程,页表也是复制的父进程的,一模一样,当修改共享的变量 g_val 时,系统会识别到该数据为共享的,此时会进行写时拷贝,重新再找一个空闲的空间给子进程的 g_val,将新空间的物理地址传给页表,修改对应的值,此时的修改与虚拟地址无关,不会互相影响

在物理意义上,地址空间其实是 32 位的地址和数据总线,按照 01 发出高频低频电信号,这些总线排列组合形成的空间范围 [0, 2 32 2^{32} 232) 就是地址空间

因此这也就能说明为什么同一变量在不同的进程中,同一地址也能对应不同的值

2.3 区域划分

在这里插入图片描述

以一个有趣的例子为例,小学同桌之间闹矛盾会画一条三八线,比如小胖和小花是同桌,这个桌子相当于进程地址空间,即 destop_area,每个人的范围即 area,有 start 也有 end,每个人的范围也是可以调大调小的

所谓的进程地址空间,本质是一个描述进程可视范围的大小,地址空间内一定要存在各种区域划分,对线性地址进行 start,和 end 即可

在这里插入图片描述

地址空间本质是内核的一个数据结构对象,类似 PCB 一样,地址空间也是要被操作系统管理的:先描述,在组织。实际存在一个 mm_struct 作为 PCB 的进程地址空间,内部有大量变量记录着地址

2.4 为什么要有进程地址空间和页表

  1. 方便每个进程以统一的视角进行操作,符合规范化的操作流程,进程地址空间将不同进程的内存隔离开来,一个进程不能随意访问和修改其他进程的内存数据,彼此的数据不会混乱
  2. 增加进程虚拟地址空间可以让我们访问内存的时候,增加一个转换的过程,在这个转化的过程中,可以对我们的寻址请求进行审查,所以一旦异常访问,直接拦截,该请求不会到达物理内存,保护物理内存

✏️比如: 对于 char 字符串、字符等,一般在编译过后是不可修改的,在代码层面上只是报错不可修改,但是在系统层面上是怎么样的呢?实际上页表里存在对于权限的记录,像字符串这类变量会被标记为仅读,当对其进行申请修改时,系统会判断该程序出错,并终止进程。除此之外页表还有关于代码数据是否被加载到内存的判断,要知道,现代操作系统为了节省空间,通常采用惰性分批加载,即按需求加载或预加载

  1. 因为有地址空间和页表的存在,将进程管理模块,和内存管理模块进行解耦合。进程地址空间属于进程管理,内存属于内存管理,操作系统对于这两的权重是不同的,所以需要页表作为中间进行过渡,实现功能的同时又互不影响

总结:进程 = 内核数据结构(task_struct && mm_struct && 页表)+ 程序代码和数据


希望读者们多多三连支持

小编会继续更新

你们的鼓励就是我前进的动力!

请添加图片描述

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值