当前位置: 首页> 游戏> 手游 > ai绘画软件免费_福州网站建设找百诚互联_企业网络营销策划案_百度指数专业版app

ai绘画软件免费_福州网站建设找百诚互联_企业网络营销策划案_百度指数专业版app

时间:2025/7/14 14:32:46来源:https://blog.csdn.net/2402_86037826/article/details/147365523 浏览次数:0次
ai绘画软件免费_福州网站建设找百诚互联_企业网络营销策划案_百度指数专业版app

文章目录

  • 1. 进程地址空间
    • 1.1 进程地址空间是什么
    • 1.2 Linux中的进程地址空间
  • 2. 虚拟地址
  • 3. 进程地址空间存在的意义
    • 3.1 安全性
    • 3.2 有序性
    • 3.3 解耦合

1. 进程地址空间

1.1 进程地址空间是什么

在学习语言的时候,我们见过这么一张图:

在这里插入图片描述
当时,我们说,这是一个程序所对应的地址空间,我们称之为程序地址空间,而这个程序地址空间,就是我们接下来要介绍的进程地址空间进程所对应的代码和数据在进程地址空间中都有相应的存储位置。

需要说明的是,上述进程地址空间基于32位的操作系统,因此,相应的空间大小为4GB左右。其中,用户可以直接访问的空间为3GB,还有1GB是内核空间,必须要通过系统调用才能访问。

1.2 Linux中的进程地址空间

与进程的task_struct相同,Linux中,同样使用一个结构体mm_struct来描述进程地址空间。

每一个进程,都有一个自己的task_struct,同时也有一个自己的mm_struct,在task_struct结构中,会有一个指针指向mm_struct

可具体是如何描述的呢?进程地址空间内部有不同的空间划分,也就是说不同的空间区域都有其对应的不同的起始和结束地址,而地址本质上就是一个数字,因此就可以使用两个数字,一个代表起始处,另一个代表结束处,来确定一个空间区域的范围。

Linux的内核源码中,确实也是这么做的。

在这里插入图片描述

但是这样的mm_struct结构会存在一个问题,它只能确定一个空间的整体范围是多少,但是并不能做到对这个空间做细分,而实质上,我们申请空间时(比如多次malloc),都是去拿到一个大空间内部的小空间,可上述做法显然不能对空间做进一步的细分。

所以,Linux中,又提供了这样一个结构vm_area_struct,来实现对大块空间的细分操作。

struct vm_area_struct {unsigned long vm_start; //虚存区起始unsigned long vm_end; //虚存区结束struct vm_area_struct *vm_next, *vm_prev; //前后指针struct rb_node vm_rb; //红⿊树中的位置unsigned long rb_subtree_gap;struct mm_struct *vm_mm; //所属的 mm_structpgprot_t vm_page_prot;unsigned long vm_flags; //标志位struct {struct rb_node rb;unsigned long rb_subtree_last;} shared;struct list_head anon_vma_chain;struct anon_vma *anon_vma;const struct vm_operations_struct *vm_ops; //vma对应的实际操作unsigned long vm_pgoff; //⽂件映射偏移量struct file * vm_file; //映射的⽂件void * vm_private_data; //私有数据atomic_long_t swap_readahead_info;#ifndef CONFIG_MMUstruct vm_region *vm_region; /* NOMMU mapping region */#endif#ifdef CONFIG_NUMAstruct mempolicy *vm_policy; /* NUMA policy for the VMA */#endifstruct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

在上图中的这个结构体中,存在两个成员vm_start和vm_end,这两个成员就是用来对空间做进一步细分的。

因此,每申请一块小空间,就要创建对应于这个小空间的vm_area_struct。所以,对于一个进程的mm_struct而言,肯定会存在多个vm_area_struct,因此mm_struct必须要将这些对象管理起来,一般会有两种管理方式:使用双链表(vm_area_struct较少时)进行管理或使用红黑树(vm_area_struct较多时)进行管理。

从上述的结构体中,vm_prev和vm_next所对应的前后指针,以及struct rb_node vm_rb所对应的红黑树结点结构,也可以看出这两种管理方式。

在这里插入图片描述

2. 虚拟地址

在大致了解进程地址空间是什么后,我们来思考一个问题,进程地址空间中对应的地址,是实际的物理地址,还是虚拟地址呢?

先说结论,进程地址空间中对应的地址,全部都是虚拟地址。

我们先来看一个示例:

在这里插入图片描述

在这里插入图片描述
在之前的学习中,我们是这样说的。父子进程之间会共享代码和数据,但由于进程之间要保持独立性,如果父子进程在后续的代码执行中,同一数据出现分歧,那么就要对这个数据变量进行分离,实际变为两个变量,一个对应父进程,一个对应子进程。

可问题是,我们在上述代码中,子进程对g_val变量进行了修改,故此时子进程中的g_val和父进程中的g_val,实质上并不是相同的变量,可是我们将其取地址并打印后,发现打印结果居然是一样的。这就说明一个事实,进程地址空间是虚拟地址,因为一个物理地址上不可能能够存储两个独立变量。

既然进程地址空间是虚拟地址,而实际存储应存储到物理内存上,这样的操作具体是如何完成的呢?

在Linux中,使用了页表这种数据结构进行虚拟内存到物理内存的映射,进而完成进程代码和数据的存储。

由于每一个进程都有其对应的页表,我们可以来更新一下关于进程的认知:进程=task_struct + mm_struct + 页表 + 相关的代码和数据。

现在,我们就能理解上述代码的运行结果了。

父进程创建子进程,子进程大部分内容都是父进程的拷贝。因此,对于g_val全局变量,它在父进程mm_struct中的虚拟地址与子进程mm_struct中的虚拟地址是相同的,在子进程未修改g_val前,它们页表中的映射也是相同的,也就是说父子进程在物理内存中,拿到的是同一个g_val。而在g_val被子进程修改后,操作系统会在这个写入操作完成之前,为子进程在物理内存中申请一块空间,用以存储另一个g_val,同时更改子进程页表,不改变虚拟地址,而是更改映射到的物理地址而取地址操作,取出的是变量的虚拟地址,这也就是为什么上述代码运行结果中,g_val地址相同,但是值不同的原因——父子进程中g_val的虚拟地址相同,但是映射到的物理地址处不同,实际已是两个变量。

上述操作实现了进程间数据层面的分离,维护了进程的独立性,而由于该操作是在子进程进行写入时发生的,因此又被叫做写时拷贝。写时拷贝是完全由操作系统自主完成的。

在这里插入图片描述

在这里插入图片描述

3. 进程地址空间存在的意义

通过上面的学习,我们明白了,进程地址空间实际上就是虚拟地址空间,因为其中的地址都是虚拟地址,并不对应物理内存。

那现在我们来思考,为什么要设计这个虚拟地址空间呢,进程直接对物理内存进行操作不行吗?

下面,我们从三个角度来阐明进程地址空间的意义。

3.1 安全性

进程地址空间的存在,使得在访问物理内存时,都要经过一次转换,即利用页表,从虚拟内存映射到物理内存。而在这个转换过程中,会由操作系统进行安全性检查,一旦断定为非法危险操作,便拒绝该操作,甚至杀死相关进程。

所以,进程地址空间的存在,使得物理内存空间不能随意被进程访问,既维护了进程的独立性,又保护了物理内存空间的安全。

3.2 有序性

我们知道,创建一个进程时,现在内存中创建相应的内核数据结构,再加载相应的代码和数据。那现在有一个问题,进程的代码和数据会被立刻全部加载吗?

一般情况下,一个进程被创建后,是不会立刻得到调度的,会有一段等待时间,而**为了提高内存空间的利用率,进程的相应代码和数据,不会立刻加载,而是等到进程即将被调度时,再加载到内存中。**同时,进程在CPU上运行时,不可能一次性用到所有代码和数据,所以进程的代码和数据也没必要一次性全部加载完,可以在进程的运行过程中,边运行边加载,这就是一种惰性加载。

所以,进程的代码和数据是分批加载到物理内存中的,物理内存是无序的,并没有严格的空间划分,理论上,进程的代码和数据可以加载到物理内存中任意还未利用到的地方。这就导致一个问题:同一进程的代码和数据加载到物理内存后,可能是散乱的。

在这种情况下,如果直接对物理内存进行管理,由于散乱的存储,相关代码和数据直接管理起来会很不方便。
而进程地址空间是有序的,有严格的空间划分,因此不管物理内存中如何存储,只要页表处理好相应的映射关系,进程从进程地址空间的角度来看待其代码和数据,始终是有序的。

所以,进程地址空间的存在,保证了进程看待其代码和数据的有序性。

3.3 解耦合

由于进程地址空间和页表的存在,实际上进程申请相关内存时,并不需要知道物理内存中的具体位置,只要管理好自身的进程地址空间,再由操作系统管理好相应页表中的映射关系,即可实现虚拟内存到物理内存之间的转换。

此时,操作系统对进程的管理与内存(物理内存)的管理之间便不再紧密联系,只要维护好相应的用于存储映射关系的页表即可。

所以,进程地址空间的存在,使得操作系统的进程管理与内存管理解耦合。

关键字:ai绘画软件免费_福州网站建设找百诚互联_企业网络营销策划案_百度指数专业版app

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: