目录
环境变量
概念
补充:命令行参数
引入
其它环境变量
理解
程序地址空间
引入
理解
虚拟地址存在意义
环境变量
概念
环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。打个比方,就像你布置房间,这些参数就类似房间里的布置规则,决定了东西怎么摆放、怎么用,能让操作系统在合适的“环境”下正常运转 。
补充:命令行参数
有参数的。就是命令行参数是在运行命令行程序时,跟随在代码名称之后输入的额外参数。这些参数用于控制程序的行为等。大家可能认为main是没有参数,实则不然实际上它
上面的argv表示命令行参数的数组,argc表示数组里内容的个数。下面是它的运行结果:
其实通过上面的大家能够发现我们在命令行输入的指令,其实是字符串。
在执行该可执行文件时,bash会创建一个子进程用来执行该程序。命令行参数会被bash解析和切分,继而bash会利用内部的机制来处理和传递这些参数信息给要执行的软件,由程序自身来存储和处理命令行参数。
通过这样实现的,通过上面就能够建立在一个函数里有不同的子功能。就是 上面是运行结果是不是感觉很熟悉,其实我们平时运用的指令,它里的选项就
引入
不知道大家有没有想过,为什么在执行系统程序时不同写路径,而我们自己写的软件就要写路径?
放在~/.bash_profile里。就是 缘于存在环境变量——PATH,它的作用是告诉体系去哪里查找。env:查看所有环境变量,echo $环境变量名:查看指定环境变量。环境变量默认
我们能够添加路径:PATH=$PATH:新路径。不要PATH=新路径否则会替换原有路径!
其大概过程是,倘若没有指定路径bash会先查看是不是内建命令,要是不是它就会去PATH里所有路径下找,如果找到了就执行该记录,没找到就会显示错误信息。补充:内建命令是在bash里面的,它是bash自己解释处理的,不需要创建子进程。
从配置文件里来的,每次从新登陆就会从配置文件里读取一次。就是 环境变量一般
其它环境变量
下面我介绍几个常用的环境变量:
- HOME:当前用户所对应的家目录(~),这就解释了为什么cd ~就会回到家目录。
- SHELL:shell所在路径,一般指的是bash所在路径
- USER:当前用户是谁,以便进行权限管理、个性化设置等操作
- LOGNAME:登录是谁,他与上面的USER在大多数情况下是一样的
- HISTSIZE:bash会记录HISTSIZE个历史命令
- HOSTNAME:登录主机名
这里我不知道为什么我没有。
- PWD:当前工作目录
- OLDPWD:上次工作目录(-)
这里我不知道为什么我没有。
理解
访问环境变量的全局变量。就是 其实依据getenv(name)也可以具体查看某环境变量,还有environ它
在bash里有一张环境变量表,它是行被子进程继承的,并且子进程的修改不影响父进程。因此环境变量具有全局性和独立性。在main函数里还有一个参数它是用来存储环境变量表(main函数里最多三个参数)。
通过export可以自己导入环境变量,unset取消自己导入的环境变量。
bash亲自执行的。就是 我上面所说的都是bash里的环境变量。但大家有没有想过export它是一个子进程啊,我用export导了一个环境变量那不是应该在子进程里吗?怎么会到bash里呢?其实export它是内建命令,它
通过 命令行是可以定义变量的(命令行定义),这种变量被称为本地变量(承受该运行有一点原因是要支撑脚本),它不会被继承,只能在当前的进程里使用。用set可以显示环境变量和本地变量,用unset也能够取消本地变量。
注意不要有空格,否则就是命令了。本地变量是可以变成环境变量的。
程序地址空间
引入
大家先看下面的代码:
是不是感觉不可思议,一块地址上竟然有两个值!实际上我们看到的地址是虚拟地址并不是物理地址,真正的物理地址用户是看不到的。
理解
一个进程有一个虚拟地址空间通过,一套页表。页表是虚拟地址到物理地址映射。于是上面的代码就能够这么理解。
一个父进程就是 首先
(上面写错了是命令行参数环境变量)继而fork一个子进程,子进程会复制父进程的PCB和页表,并自己做出一些修改
当子进程对val修改后
虚拟地址空间的大小在32位机器上是4G,一般是用户用3G,内核用1G。进程会以为自己占据了整个内存。它里面的区域划分包括如代码段、数据段、堆、栈等。环境里的每个进程都会有自己的进程地址空间。
通过 补充:能够简单认为进程地址空间和虚拟地址空间是一回事。但严格来说,虚拟地址空间是机制,进程地址空间是实例。也就是说进程地址空间是虚拟地址空间在单个进程中的具体实现。
操作系统会对进程地址空间进行管理,那怎么管理呢?依然是先描述在组织,所以PCB里有mm_struct,它是对进程地址空间的描述。
mm_struct是Linux内核中用于描述进程内存空间的数据结构。它包含了进程虚拟地址空间的各种信息。它里面主要是记录区域的开始位置和结束位置。当想调整某区域时,只需要改变起始位置和结束位置即可。
堆,其它的区域也会用vm_area_struct表示区域范围。vm_area_struct通过双链表和红黑树管理起来。就是 堆是不连续的,我们需要记录每一个堆的开始和结束位置。但是在mm_struct里只有一对用于记录堆的开始和结束位置,那如果我又用malloc开辟了一段空间,那该怎么办呢?其实在mm_struct里有vm_area_struct它表示一个独立的虚拟内存区域。所以不管开辟多少空间只要求用vm_area_struct连接起来即可。其实不仅
更细致地表示虚拟地址空间中的每一个具体的、独立的虚拟内存区域,它描述了每个区域的具体属性。就是 mm_struct是对进程整个虚拟地址空间进行宏观的,整体的描述和管理。 vm_area_struct
int有4个字节,它占据了4个虚拟地址。在取它地址时为什么只返回一个地址?其实系统会返回地址最小的那种值,剩下的可以通过偏移量来计算出来,因此才会有类型这一说。
虚拟地址存在意义
- 工具的各个部分(如代码段、数据段等)在物理内存上的存储位置可能是不连续、无序的,但我们通过虚拟地址来看就是有序的。
- 在地址的转化过程中,会对你的地址和管理进行合法性判断,从而保护物理内存。
比如:
当你拿野指针去查页表,页表里面并没有该地址,应用就会崩溃(也不是说一定会崩溃,可能你的野指针正好在页表里,这其实比崩溃还可怕)。
当执行char* str = "hello"; *str = 'H'; 时,查页表时会发现str只有只读权限没有修改权限,程序就会崩溃。
- 让进程管理和内存管理进行一定程度的解耦和。
通过 有了虚拟地址之后我们就不用把所有的代码和数据给一次性都给加载到物理内存里,而是分批次加载,甚至能够不加载,让进程只有PCB和页表,这时去查页表时如果物理地址为空就会发生缺页中断,进程会停下来等页表补充完后再次执行。