【Linux】进程的地址空间

再讲进程的虚拟地址空间之前,我们先来了解一下程序的地址空间是什么?

程序的地址空间

在这里插入图片描述
这是程序地址空间。而程序是一个个死的代码,所以叫做程序地址空间不合适。程序运行起来之后,才会占用内存。所以我们称为进程地址空间
那么我们思考一下,进程地址空间每一个进程都有一个,凭什么每一个进程都会有4G的大小,那么是内存不够用的。

父子进程中的数据独有,代码共享,但是通过代码实现可以在父子进程中实现对全局变量进行修改,也可以通过打印的方式看出父子进程中的同一变量的地址相同,那为什么一个一块空间可以有两个值 ?

其实,在程序中所获得的变量地址都是假地址。因为这个地址空间都是假的。所以我们叫它 进程的虚拟地址空间

进程虚拟地址空间的含义:

进程虚拟地址空间:是操作系统为进程描述的一个假的地址空间。目的是为了让进程认为自己拥有一块连续的线性的完整的地址空间。但是实际上一个进程使用的内存并非连续存储的,而是通过页表映射了虚拟地址与物理地址之间的关系。为了让进程通过页表获取物理地址,进而实现数据的离散式存储。

进程的虚拟地址空间的作用:

  1. 物理内存的离散式存储,提高内存利用率

我们知道数据的对应关系,就可以离散式存储,利用内存空间。但是程序运行起来还是需要连续的地址,操作系统为一个程序提供一个线性虚拟的地址,在虚拟的地址中,程序的所有数据都是线性连续存储,但是在物理内存中,程序运行时所要的数据都是离散式存储的,所以操作系统在物理内存与虚拟内存之间建立了一个映射关系,提高了内存的利用率。
这个映射关系就是页表。所以虚拟地址空间可以通过页表直接映射到物理地址空间,这样就可以寻找程序运行时所要的数据变量。

  1. 保证了进程的独立性,每一个进程都只能访问自己虚拟地址映射的物理内存

直接在物理内存上修改,不仅内存利用率低,而且会缺乏内存的访问控制。大家都可以对同一块内存上修改,这样操作不安全,那么就会缺乏访问控制。

  1. 页表可以进行内存的访问控制,页表可以对每个虚拟地址进行权限标记。
    1. 页表中可以规定物理内存上的数据是否可以读写,页表中若查到你要修改只读数据,那么就是内存访问错误。
    2. 当对nullptr空指针访问时,程序发生段错误。物理地址上0号位置实际上是有空间的。 其实nullptr是一个虚拟地址,当你访问nullptr虚拟地址时,不能读写,是虚拟地址空间规定。
      进程的虚拟地址空间都是通过页表来访问自己映射的那块内存,其它的程序不能访问,这样就保证进程之间相互独立,独立就代表着稳定。

我们接下来看父子进程中如何通过虚拟地址空间实现数据独有?

虚拟地址空间其实也是我们描述出来的,通过mm_struct结构体(PCB),记录每一个分区段的位置和大小,这个mm_struct * 也就是进程的内存指针 。因为虚拟地址空间是靠很多区域的位置信息描述出来的,所以有时候也叫做内存描述符

进程之间为什么能通过虚拟地址空间空间实现数据独有?

在这里插入图片描述

一开始的时候,通过PCB描述的进程1和进程2上的变量val都是100,在进程1和进程2的虚拟地址空间上都是相同的位置,所以我们在程序中看到的变量val的地址相同,其实是虚拟地址,假地址。此时通过页表映射到物理内存中的相同位置,但是当进程1改变val值的时候,就不一样了。

注意这里的进程1和进程2也可以是父子进程

在这里插入图片描述
当进程1通过页表映射要修改val值的时候,页表会根据权限,知道进程1要修改数据,所以会先在物理内存上重新开一块空间,并且将val值拷贝到新空间上,此时更新进程2的页表映射,使进程2上的val值映射到物理内存上新的位置。在此过程中,进程1和进程2的虚拟地址空间上val的空间是不会改变的。所以进程间就实现了数据独有。

写时拷贝技术:等到需要更改数据时,再去申请内存,重新拷贝一份,并且更改页表的对应关系。

写时拷贝的原因是:提高进程创建的效率,有可能多个进程只是读数据,并不修改这个数据。所以用的时候再去开辟新的内存,拷贝数据。提高效率。

我们再来捋一下如何创建子进程,使得数据独有?
创建一个子进程的流程: 写时拷贝技术

  1. 创建pcb
  2. 拷贝父进程中的pcb的数据(拥有相同的虚拟地址空间,相同的页表)
  3. 父子进程一开始映射同一块物理内存
  4. 等到物理内存修改时,才为子进程重新开辟内存,拷贝数据。

为什么代码共享而数据独有
因为进程的虚拟地址空间中代码段是相同的,不会修改,所以一直映射同一块物理内存中。

虚拟地址的构成:页号 + 页内偏移
页面: 4096 物理内存:4G
所以一共有1024*1024个页表项,页表项也是结构体数组,如果一个页表要开这么大一个空间,那就太浪费了。因为用不到这么多的映射关系,所以就消耗资源。
二级页表的引入
所以有了二级页表,这块页表用到多少页表项,这块页表的内存通过另一块页表来映射,用到了才为页表分配这块内存,用不到就不分配了,提高内存利用率。

三种内存管理方式

内存管理:
分段式:对程序比较友好,但是内存利用率不高
分页式:提高内存利用率
段页式:目前采用的方案

分段式
在这里插入图片描述

分页式
在这里插入图片描述
段页式
在这里插入图片描述

物理地址的计算方法: 虚拟地址/页面大小 = 页号。 通过页表得到块号,块号*块大小 + 页内偏移(虚拟地址%页面大小)

猜你喜欢

转载自blog.csdn.net/weixin_43939593/article/details/105982196