Linux——补充点(进程切换及页表映射)

c5e075ebb8cf4510b629b9a74ab7e1fa.png

目录

补充点1:进程地址空间堆区管理

补充点2:Linux内核进程上下文切换

补充点3:页表映射

补充点4:两级页表


 

补充点1:进程地址空间堆区管理

        Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息。该结构体存放在叫做任务列表的双向循环列表中!

 

所学习过的包含:

        进程标识符 - 进程优先级 - 进程状态 - 进程地址空间 - 文件描述符表 -  进程信号位图 - CPU寄存器的上下文数据 - 进程相关页表(内核级页表、用户级页表)

60dc7914c6bf419ab3a52d0fd878cb14.png

        在进程地址空间中,栈区,代码区等一部分区域,是被整体所使用的!而堆区具有更细粒度的划分,包括使用者等(参考文章:Glibc——堆利用机制[拓展]_IfYouHave的博客-CSDN博客),因此堆是使用一个vm_area_struct小的结构体进行区分,使用双链表的形式进行管理!

836c487f5d0f4a3db512183bbe9ee12a.png

(参考文章:linux内核学习笔记-struct vm_area_struct_struct vm_area_struct source code_带着耳机去梦游的博客-CSDN博客)

0b599703f46b4309951fcf05d1aba35a.png

        在进行堆区申请空间,上层调用malloc函数 - 底层调用brk系统调用,就会申请一个vm_area_struct,内有start表针虚拟地址起始,end表示虚拟地址结束,经过页表映射至内存。

        堆区典型特征:申请的空间连续!

OS是可以做到让进程进行资源细粒度划分的

补充点2:Linux内核进程上下文切换

        进程上下文是进程执行活动全过程的静态描述。我们把已执行过的进程指令和数据在相关寄存器与堆栈中的内容称为进程上文,把正在执行的指令和数据在寄存器与堆栈中的内容称为进程正文,把待执行的指令和数据在寄存器与堆栈中的内容称为进程下文。

        实际上linux内核中,进程上下文包括进程的虚拟地址空间和硬件上下文。

 

        进程硬件上下文包含了当前cpu的一组寄存器的集合,arm64中使用task_struct结构的thread成员的cpu_context成员来描述,包括x19-x28,sp, pc等。

a6b5eb925f194e3db31e2ca2e1cf4462.png

        进程上下文切换主要涉及到两部分主要过程:进程地址空间切换和处理器状态切换。地址空间切换主要是针对用户进程而言,而处理器状态切换对应于所有的调度单位。

进程地址空间切换:

        进程地址空间内有进程运行的指令和数据,因此到调度器从其他进程重新切换到我的时候,为了保证当前进程访问的虚拟地址是自己的必须切换地址空间。

        进程pcb内mm_struct结构体将各个vma组织起来进行管理,其中有一个成员pgd至关重要,地址空间切换中最重要的是pgd的设置。pgd中保存的是进程的页全局目录的虚拟地址,那么pgd的值是何时被设置的呢?

        答案是fork的时候,如果是创建进程,需要分配设置mm_struct,其中会分配进程页全局目录所在的页,然后将首地址赋值给pgd,完成了这一步,也就完成了进程的地址空间切换,确切的说是进程的虚拟地址空间切换。

处理器状态(硬件上下文)切换:

        处理器状态切换就是将前一个进程的sp,pc等寄存器的值保存到一块内存上,然后将即将执行的进程的sp,pc等寄存器的值从另一块内存中恢复到相应寄存器中,恢复sp完成了进程内核栈的切换,恢复pc完成了指令执行流的切换。

        其中保存/恢复所用到的那块内存需要被进程所标识,这块内存这就是cpu_contex这个结构的位置(进程切换都是在内核空间完成)。

 

线程部分会学习:

        内核线程,不需要切换地址空间,只进行硬件上下文切换

        所有的进程线程之间进行切换都需要切换处理器状态。

        对于普通的用户进程之间进行切换需要切换地址空间

        同一个线程组中的线程之间切换不需要切换地址空间,因为他们共享相同的地址空间。
        内核线程在上下文切换的时候不需要切换地址空间,仅仅是借用上一个进程mm_struct结构。(参考文章:深入理解Linux内核进程上下文的切换 - 知乎 (zhihu.com))

补充点3:页表映射

        MMU(Memory Management Unit),即内存管理单元,是一个硬件,是现代CPU架构中不可或缺的一部分,MMU主要包含以下几个功能:

  • 虚实地址翻译
在用户访问内存时,将用户访问的虚拟地址翻译为实际的物理地址,以便CPU对实际的物理地址进行访问。
  • 访问权限控制
可以对一些虚拟地址进行访问权限控制,以便于对用户程序的访问权限和范围进行管理,如代码段一般设置为只读,如果有用户程序对代码段进行写操作,系统会触发异常。
  • 引申的物理内存管理
对系统的物理内存资源进行管理,为用户程序提供物理内存的申请、释放等操作接口。

使用MMU带来的好处或者优势:

  • 提升物理内存的利用率
物理内存按需申请,如代码段的内存在执行时进行映射和转换,进程fork后,t通过写时复制(Copy-On-Write)进行真正的物理内存分配。解决内存管理碎片化的问题,即在系统运行一段时间后,频繁的内存申请和释放会导致内存碎片化,无法申请到一块足够大的地址连续的内存。
  • 对内存地址的访问进行控制
如上述代码段只读权限控制,多线程的栈内存之间的空洞页隔离可以防止栈溢出后改写其他线程的栈内存,不同进程之间的地址隔离等等。
  • 将进程的地址空间隔离
不同进程之间可以使用相同的虚拟内存地址空间,而进程间的物理内存又可以做到隔离,这保证了进程的独立性同时,又简化了地址的访问方式,如在早期32位CPU上,为了支持4G以上的物理内存,一般物理地址有36-bit(如PowerPC-604系列),但是用户的虚地址仍然使用32-bit,做法就是将用户的不同进程的32-bit虚地址在MMU转换时,转换为36-bit的物理地址,这样每个进程仍然能访问0-3G虚地址范围,将多个进程的3G空间映射到36-bit的物理内存空间中去。

上述参考文档(MMU原理 - page)

 

如何从虚拟地址映射到物理内存?

4aeb7c2b0c444c9a83db2c00c60e25df.png

  1. .exe就是一个文件
  2. 我们的可执行程序本来就是按照地址空间方式进行编译的(编译形成二进制文件的格式 - ELF格式)
  3. 可执行程序,其实按照区域也已经以4KB为单位进行了划分
  4. 物理内存也早就按照4KB为单位划分成一个个page(操作系统进行IO的基本单位就是4KB)
  5. 因为被划分,操作系统就需要管理划分后每一块物理内存的属性等,先描述,在组织,page。因此4G的物理内存,便会形成100w+个块,假设一个结构体为20字节,100w+个page会使用20MB的内存空间

        

8fc731efcc6a4cc4bba9ad7b76a955bf.png

磁盘内文件以4KB为单位划分的块成为页帧,物理内存划分块称为页框

IO基本单位是4KB,就是将页帧内容 -> 页框

补充点4:两级页表

        页表在进行映射时,会通过虚拟地址,访问物理内存,页表中含有其他字段,表征磁盘数据是否被加载到内存,没有,变会进行申请内存page,通过文件系统加载内存,最后填充在页表右侧,这种行为为缺页中断!(用户零感知)

        4.1 单级页表存在的问题:

77a6fa26f6744412bc201316605e05cb.png

        若计算机系统按字节寻址,支持32位逻辑地址,采用分页存储管理,页面大小为4KB,页表项长度为4B。4KB = 2^12B,因此页内地址要用12位表示,剩余20位表示页号。

        物理内存 4GB = 2^20 * 2^12 B

        因此,该系统中用户进程最多有2^20页。相应的,一个进程的页表中,最多会有2^20个页表项,所以一个页表最大需要2^20 * 4B = 2^22B。一个页框(内存)大小为4KB,所以需要2^22/2^12 = 2^10个页框存储该页表。

        而页表的存储是需要连续存储的,因为根据页号查询页表的方法:

        K号页对应的页表项的位置 = 页表起始地址 + K * 4B(页表项长度),所以这就要求页表的存储必须是连续的。

        

498e9ce2d59f4c6e8bb0a70d9ad8281c.png

        回想一下,当初为什么使用页表,就是要将进程划分为一个个页面可以不用连续的存放在内存中,但是此时页表就需要1024个连续的页框,似乎和当时的目标有点背道而驰了....
          此外,根据局部性原理可知,很多时候,进程在一段时间内只需要访问某几个页面就可以正常运行了。因此也没有必要让整个页面都常驻内存。
          所以,单级页表存在以上两个问题。

        (参考文章:两级页表 - 简书 (jianshu.com))

       

948262c8f65948bba6d8fa70d61e340a.png

        4.2 两级页表:

        如何解决页表过大需要连续存储的问题呢?这个问题可以参考进程太大需要连续存储的答案。因为页表必须连续存放,所以可以将页表再分页。
         解决方案:可以将长长的页表进行分组,使每个页面中刚好可以放下一个分组(如上面的例子中,页面的大小4KB),每个页表项4B,所以每个页面中可以存放1K个(1024)个页表项,因此每1K个连续的页表项为一组,每组刚好占一个页面,再讲各组离散的放在各个内存块中)。这样就需要为离散的页表再建立一张页表,称为页目录表,或外层页表,或顶层页表。

        32位的逻辑地址空间,页表项大小为4B,页面大小4KB,则页内地址占12位

        将页表分为分为1024个表,每个表中包含1024个页表项,形成二级页表。二级页表结构的逻辑地址结构如下图

365e8382d9b941719680f0ec42a6bfb4.png

       

两级页表如何实现地址转换:

(1) 按照地址结构将逻辑地址拆成三个部分。
(2) 从PCB中读取页目录起始地址,再根据一级页号查页目录表,找到下一级页表在内存中存放位置。
(3) 根据二级页号查表,找到最终想要访问的内存块号。
(4) 结合页内偏移量得到物理地址

7613f98d58514bcc96510407dee8bc8f.png

下面以一个逻辑地址为例。将逻辑地址(0000000000,0000000001,11111111111)转换为物理地址的过程。

8aaf8cf468d14bf6ab6837f84204b477.png

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/92036.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

keil调试的时候没问题,下载时候没反应

今天遇到这样一个问题。我下载商家的代码例程后单片机没反应,进入调试的时候一切正常。很奇怪,在网上找了教程问题解决,总结一下。 原因在于程序下载进去后没有按下复位键,导致还是之前的程序。我之前设置的是下载后自动复位运行…

【STL】用一棵红黑树封装map和set

⭐博客主页:️CS semi主页 ⭐欢迎关注:点赞收藏留言 ⭐系列专栏:C进阶 ⭐代码仓库:C进阶 家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我…

玩转gpgpu-sim 04记—— __cudaRegisterBinary() of gpgpu-sim 到底做了什么

官方文档&#xff1a; GPGPU-Sim 3.x Manual __cudaRegisterBinary(void*) 被执行到的代码逻辑如下&#xff1a; void** CUDARTAPI __cudaRegisterFatBinary( void *fatCubin ) { #if (CUDART_VERSION < 2010)printf("GPGPU-Sim PTX: ERROR ** this version of GPGPU…

asp.net core mvc区域路由

ASP.NET Core 区域路由&#xff08;Area Routing&#xff09;是一种将应用程序中的路由划分为多个区域的方式&#xff0c;类似于 MVC 的控制器和视图的区域划分。区域路由可以帮助开发人员更好地组织应用程序的代码和路由&#xff0c;并使其更易于维护。 要使用区域路由&#…

小程序如何设置余额充值

在小程序中设置余额充值是一种非常有效的方式&#xff0c;可以帮助商家吸引更多的会员并提高用户的消费频率。下面将介绍如何在小程序中设置余额充值并使用。 第一步&#xff1a;创建充值方案 在小程序管理员后台->营销管理->余额充值页面&#xff0c;添加充值方案。可…

Spark性能监测+集群配置

spark-dashboard 参考链接 架构图 Spark官网中提供了一系列的接口可以查看任务运行时的各种指标 运行 卸载docker https://blog.csdn.net/wangerrong/article/details/126750198 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest…

Linux系统编程(七):线程同步

参考引用 UNIX 环境高级编程 (第3版)黑马程序员-Linux 系统编程 1. 同步概念 所谓同步&#xff0c;即同时起步、协调一致。不同的对象&#xff0c;对 “同步” 的理解方式略有不同 设备同步&#xff0c;是指在两个设备之间规定一个共同的时间参考数据库同步&#xff0c;是指让…

小白继续深入学习C++

第1节 指针的基本概念 1、变量的地址&#xff1a; 变量是内存地址的简称&#xff0c;在C中&#xff0c;每定义一个变量&#xff0c;系统就会给变量分配一块内存&#xff0c;内存是有地址的。 C用运算符&获取变量在内存中的起始地址。 语法&#xff1a; &变…

Hive 常见数据倾斜场景及解决方案(Map\Join\Reduce端)

目录 MapReduce流程简述a) Map倾斜b) Join倾斜c) Reduce倾斜 首先回顾一下MapReduce的流程 MapReduce流程简述 输入分片&#xff1a; MapReduce 作业开始时&#xff0c;输入数据被分割成多个分片&#xff0c;每个分片大小一般在 16MB 到 128MB 之间。这些分片会被分配给不同的…

移动手机截图,读取图片尺寸

这个代码的设计初衷是为了解决图片处理过程中的一些痛点。想象一下&#xff0c;我们都曾遇到过这样的情况&#xff1a;相机拍摄出来的照片、网络下载的图片&#xff0c;尺寸五花八门&#xff0c;大小不一。而我们又渴望将它们整理成一套拥有统一尺寸的图片&#xff0c;让它们更…

ChatGPT 调教指南:从 PDF 提取标题并保存

一、请使用python编写一段代码&#xff0c;使用pymupdf包从pdf中提取标题&#xff0c;保存标题名称和页数。 我没有加任何的答案提示&#xff0c;看看 GPT 如何反应。它应该是知道 PDF 没有任何语义信息&#xff0c;一切标题或者正文全是文本框。 好的&#xff0c;以下是使用py…

零基础Linux_9(进程)环境变量+进程地址空间+进程创建fork

目录 1. 环境变量 1.1 环境变量基本概念 1.2 环境变量PATH 1.3 环境变量HOME和SHELL 1.4 获取环境变量&#xff08;main函数参数&#xff09; 1.4.1 main函数第三个参数 1.4.2 设置普通变量和环境变量 1.4.3 main函数前两个参数 2. 进程地址空间 2.1 验证进程地址空…

PHP8的数据封装(数据隐藏)-PHP8知识详解

面向对象的特点之一就是封装性&#xff0c;也就是数据封装&#xff0c;也被称为数据隐藏。 php8通过限制访问权限来实现数据的封装性&#xff0c;这里用到了public、private、protected、static和final几个关键字。下面来介绍前3个。 1.、public&#xff08;公共成员&#xf…

CSP-J第二轮试题-2021年-3题

文章目录 参考&#xff1a;总结 [CSP-J 2021] 网络连接题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 样例 #3样例输入 #3样例输出 #3 样例 #4样例输入 #4样例输出 #4 提示答案1答案2 现场真题注意事项 参考&#xff1a; https://www…

2022年全球一次能源消费量:石油消耗量持续增加达190.69百亿亿焦耳,亚太地区消费量居首位[图]

一次性能源是指从自然界取得未经改变或转变而直接利用的能源。如原煤、原油、天然气、水能、风能、太阳能、海洋能、潮汐能、地热能、天然铀矿等。一次性能源又分为可再生能源和不可再生能源&#xff0c;前者指能够重复产生的天然能源&#xff0c;包括太阳能、风能、潮汐能、地…

网络知识点之—PPPoE

本文章已收录至《网络》专栏&#xff0c;点进右上角专栏图标可访问本专栏 PPPoE&#xff08;Point-to-Point Protocol Over Ethernet&#xff09;&#xff0c;指以太网上的点对点协议&#xff0c;是将点对点协议&#xff08;PPP&#xff09;封装在以太网&#xff08;Ethernet&a…

机器学习的超参数 、训练集、归纳偏好

一、介绍 超参数&#xff08;Hyperparameters&#xff09;和验证集&#xff08;Validation Set&#xff09;是机器学习中重要的概念&#xff0c;用于调整模型和评估其性能。 超参数&#xff1a; 超参数是在机器学习模型训练过程中需要手动设置的参数&#xff0c;而不是从数据…

C/C++与汇编混合编程

1. C/C调用汇编 C/C想调用汇编代码必须要注意名称修饰的问题 名称修饰(name decoration): 一种标准的C/C编译技术, 通过添加字符来修改函数名, 添加的字符指明了每个函数参数的确切类型。主要是为了支持函数重载, 但对于汇编来说其问题在于, C/C编译器让链接器去找被修饰过的名…

K8S-EverNote同步

Node污点 释义看文档就好 https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/ 污点是Node的属性 容忍度是Pod的属性 用来标记各自特征的&#xff0c;通常协同工作。 举个例子&#xff0c; 一个Node的污点 kubectl taint nodes node1 key1v…

算法练习10——数组为空的最少操作次数

LeetCode 100032 使数组为空的最少操作次数 给你一个下标从 0 开始的正整数数组 nums 。 你可以对数组执行以下两种操作 任意次 &#xff1a; 从数组中选择 两个 值 相等 的元素&#xff0c;并将它们从数组中 删除 。 从数组中选择 三个 值 相等 的元素&#xff0c;并将它们从数…