本次是理解进程概念的最后一个章节,今天要给大家介绍的是环境变量和程序地址空间两方面的内容,本章内容大部分以概念为主,需要大家反复观看。

       由于上一章结束的比较匆忙,我们再来回顾一下孤儿进程,孤儿进程就是父进程先于子进程退出,子进程就会成为孤儿进程。由于进程之间都是独立运行的,在父进程创建好子进程后,两个进程可以独立运行,互不影响运行过程;但其实在后台,会有一个1号进程成为所有孤儿进程的父进程,致使孤儿进程再退出后不会成为僵尸进程。(就好比1号父进程就是孤儿院院长,他会不断接纳孤儿进程,并且十分负责)

       下来就是我们以后经常要用到的守护进程,也可以叫精灵进程。该进程就是一种特殊的孤儿进程,运行在后台(不占用终端),并给自己创建新的对话,不会影响到当前登录终端时所创建的登录会话(一个登录会话就是一段时间,相当于我们登录上linux,直到我们断开linux连接),不受终端的任何影响,在背后进行一些任务的处理。

       讲完上章我们所遗漏的知识,我们现在来讲解今天的知识:环境变量,环境变量就是保存当前运行环境参数的一些变量,可以让环境配置更简单。

举个例子,但我们在Linux上写一一串代码,并执行

理解进程概念—3_虚拟地址

会发现我们写的代码不能像ls(打开目录)一样直接打开,必须要明确路径才能成功运行

理解进程概念—3_虚拟地址_02

那么,为什么我们不能像ls一样直接运行我们的程序呢???

原因就是我们的print文件并不在系统的默认查找位置,而ls却在其中,这时我们就要介绍我们的第一个环境变量——PATH

PATH环境变量:作用就是保存系统的程序默认查找路径,将我们自己的程序所在路径加入其中,这样我们在运行自己的程序时就不用加入路径了代码如下:

理解进程概念—3_虚拟地址_03

       我们将当前存有print文件的路径加入到/usr/bin中,echo查看系统默认路径就会显示我们当前路径,这就说明添加成功;我们就可以直接打出print了。

我们再来介绍几个简单的命令:

env                                     查看所有环境变量

echo $变量名称                  打印指定的环境变量内容($声明后方为一个变量)

set                                       查看当前环境中的所有变量(包换环境变量和普通变量)

名称=数字                           在shell环境中添加普通变量

export 名称                         声明一个变量为环境变量

unset 名称                           移除指定的环境变量

       注意!!环境变量和普通变量的区别:在程序中可以获取到当前环境的环境变量数据,但获取不到普通变量的数据。每个终端都有自己独立的环境变量,互不影响,在一个终端中设置环境变量,其他终端并不会产生。(就算我们用一个账户开启两个会话,在第一个会话中声明一个环境变量,在第二个会话中也不会有这个环境变量出现)

环境变量在进程之间具有一定的传递性,可以通过设置环境变量向进程传递数据。

接下来我们要将到除进程概念外另一个非常重要的知识点:程序地址空间

理解进程概念—3_环境变量_04

上图为程序的地址空间,

       通过冯诺依曼体系结构我们可以知道,程序本身是不占内存的,只有运行起来才会被加载到内存中,才能占用空间;因此程序地址空间应该被称为——进程地址空间

下面我们来看一个代码:

理解进程概念—3_虚拟地址_05

从代码来看,我们应该不难看出child的g_val应该和parent的g_val值相同,地址也相同;那么实际是什么样的呢??

理解进程概念—3_地址空间_06

我们可以看到,当我们运行代码后会发现一个有趣的事:在同一块地址上,会有两个不一样的值!!

       在我们以前写代码时,一块空间就只能有一个值,这是肯定的,那么这里为什么会有两个不一样的值呢,是电脑的问题嘛?其实是这样的:在进程的内部我们所访问的空间地址实际上都是假地址,而进程地址空间其实是一个虚拟的地址空间,在进程中使用的地址都是虚拟地址空间中的地址。

那么问题来了,为什么要用虚假的地址空间呢??如何实现虚假的地址空间??

       那么这时候,我们以大家熟知的百度网盘举例:我们现在一个用户大约有100G,按1亿人有这么大的内存,按一个硬盘有4T,那么百度可能有这么多的硬盘吗?再算成本,市面上一个4T的硬盘大概2000快,那百度的成本就是50亿了。

       实际上百度使用了共用空间的,每个人使用多少,就会分多少空间给你,不hi直接开辟一段专属于你的空间;这样就可以大大节省空间的使用效率。(其实也就是告诉你,你有完整的100G可以使用,但实际上是,你用多少,我给你多少内存。)你所访问的是一个虚拟地址,在物理和虚拟地址空间之间建立一个映射关系实现离散存储数据,这样就可以做到虚拟访问的地址空间和实际存储的物理地址不同,实现离散存储数据。(完美利用空间碎片)

理解进程概念—3_地址空间_07

       因此使用虚拟地址空间,可以使内存利用率提高,每个进程都有自己独立的虚拟地址空间,虚拟地址随意使用,不用担心与其他地址冲突,并且还可以在虚拟和物理映射做出内存访问,切记,虚拟地址空间只是对物理地址空间继进行的描述。

理解进程概念—3_虚拟地址_08

那么虚拟地址空间如何实现呢——虚拟地址空间的本质??

       我们可以知道虚拟地址空间,就是有操作系统为每个进程虚拟描述了一个地址空间,或者说,虚拟地址空间,就是操作系统为进程进行虚拟空间维度的划分描述,这个描述就是一个mm_struct结构体。

理解进程概念—3_地址空间_09

       这里会涉及到一个方法:写实拷贝技术,就是空间中原本访问的是同一块代码,但是当空间中数据发生改变时,就要为子进程重新开辟一个空间,将数据拷贝进去,修改映射关系。

       接下来我们来讲解虚拟内存空间和物理内存之间是如何映射的——内存管理方式,在我们的系统中,总共由三类内存管理方式:分段式内存管理,分页式内存管理和缺页中断内存管理。

       首先来看分段式内存管理:将虚拟地址空间进行分段,划分为代码段,数据段........;目的就是便于编译器进行地址管理(一个程序除了动态申请之外,其地址都是在编译完成前就确定的);而实现的方式就是将虚拟地址空间分段为段号和段内地址。

理解进程概念—3_环境变量_10

由上图可知,物理块起始地址+段内偏移(段内地址)=变量的实际存储地址

接下来看分页式内存管理:将虚拟内存地址空间进行更加细致的分页管理,一个内存页默认4096个字节

理解进程概念—3_环境变量_11

与分段式内存管理类似,物理起始地址+页内偏移=变量的物理存储地址,找到之后会判断是否具有权限,是否触发缺页中断(当前要访问的数据不在物理内存中,触发缺页中断,将需要的数据从交换分区重新加载)

分页式划分更加细致,实现数据经过页表映射后,在物理内存上的离散存储,提高内存的利用率,并在页表映射中进行内存访问控制

最后就是段页式:将地址空间进行分段,每个分段内采取分页管理(分页+分段),地址组成为段号+段内页号+页内偏移。

       该方法是通过段号找到段表项,段表项中记录了对应段的页表位置,再通过段内页号找到页表中的页表项,通过页表项中的物理块地址+页内偏移得到变量的物理存储地址

好了,以上的内容就是我们进程概念的最后两个知识,可以结合我之前的文章看,如有不对,希望给位大佬在评论区多多讨论,感谢观看!!