一、认识常见的环境变量
1. echo $HOME
输出当前用户对应的家目录
当用户登录系统时,流程如下:
(1)用户登录系统后,系统启动Shell程序。
(2)启动bash shell,准备接收用户指令。
(3)在bash启动过程中,它会读取环境变量配置文件,如 .bashrc 或 .profile 等。
(4)从配置文件中加载重要的环境变量,例如 PATH 和 HOME :
PATH变量定义了命令的搜索路径,使得用户可以运行各种程序。
HOME变量指定了用户的主目录,通常为 /home/usr(usr 应由实际的用户名代替)。
(5)需要注意的是,bash本身也是一个进程,它在操作系统中运行并具有唯一的进程ID。
(6)当bash进程启动时,它会设置当前工作目录(cwd),即当前所在的目录位置。
(7)通常情况下,登录后的bash进程的当前工作目录会设置为用户的主目录,
例如 cwd -> /home/usr。
(8)用户在命令行输入的每一条命令,都会被bash进程解析并执行。
这些命令实际上是bash进程的子进程,它们继承了bash进程的环境变量和权限。
2. echo $SHELL
命令的作用是输出当前用户的默认shell的路径。
3. USER
在Linux操作系统中,环境变量USER是用来存储当前登录用户的用户名的。
在编写Shell脚本或程序时,可以使用$USER获取当前登录的用户名,并根据不同的用户执行不同的操作。
二、理解环境变量
系统提供的具有“全局属性”的变量
1. 环境变量和本地变量
export 可以将本地变量导出到环境变量。
环境变量是可以被子进程继承下去的,而本地变量不行。
【Q】那么 fork() 创建的子进程呢?
【A】环境变量可以被所有bash之后的进程看到,所以环境变量具有全局属性。
这样设计的理由如下:
(1)系统的配置信息,尤其是具有“指导性”的配置信息,它是系统配置起效的一种表现
(2)进程具有独立性,环境变量可以用来在进程间传递数据(只读数据)
2. environ
environ 被定义为一个指向 char * 的指针数组,这意味着它是一个指向字符串数组的指针。每个字符串表示一个环境变量,格式为 "NAME=value"
由于 environ 是一个全局变量,因此不需要显式地声明它,但是可以通过 extern 关键字来声明以便使用它
extern char **environ;
这行代码告诉编译器 environ 是一个已经存在的指针数组,可以用来访问环境变量。
遍历方法如下:
int i = 0;
for (; environ[i]; ++i) {
printf("environ[%d]: %s\n", i, environ[i]);
}
三、进程地址空间 Pt.1
1. 地址空间
高地址
命令行参数 环境变量 |
栈 |
⬇️ |
共享区 |
⬆️ |
堆 |
未初始化数据 |
初始化数据 |
正文代码 |
低地址
进程地址空间不是程序地址空间
- 操作系统让每一个进程都认为自己是独占系统物理内存大小,进程彼此之间不知道,不关心对方的存在,从而实现一定程度的隔离
- 先描述再组织:所谓的进程虚拟地址空间,本质是一个内核数据结构对象(类似PCB)
2. 区域划分
struct destoproom{
int start_part1, end_part2;
int start_part2, end_part2;
};
struct destoproom part = {1, 50, 51, 100};
区域划分的本质:告知开始和结束即可
3. 地址空间上的地址
2^32*1 字节 = 4 GB
一共会存在2^32个地址
- 地址本质上就是一个数字,可以被保存为unsigned long(4字节)
- 空间范围内的地址,可以随便用,暂时不需要记录它的地址
操作系统会构建页表,构建虚拟地址和物理地址的映射关系
struct mm_struct + 页表 = 虚拟内存管理方案
父子进程映射到同样的代码内存区域,所以父子进程代码共享(类似浅拷贝)
故在父子进程不修改变量时,数据其实也是共享的
修改 ➡️ 写入 ➡️ 进程具有独立性 ➡️ 把目标内存拷贝一份,修改物理地址,重新建立映射,但虚拟地址不变,上述过程由OS自主完成,被称为写时拷贝机制
进程 = 内核数据结构(task_struct, mm_struct, 页表)+ 自己的代码和数据
进程的独立性:内核数据结构各自一份,代码和数据也是独立的