进程地址空间与页表方面知识点(缺页中断及写时拷贝部分原理)

news/2025/3/28 23:36:47/

谢谢阅读,如有错误请大佬留言!!

目录

谢谢阅读,如有错误请大佬留言!!

抛出总结

开始介绍

发现问题

进程地址空间(虚拟地址)

页表

物理内存与进程地址空间映射

缺页中断基本概念

写时拷贝的原理(基于缺页中断)


抛出总结

进程:何为进程进程 = 内核数据结构(PCB+mm_struct+页表(MMU))+ 代码和数据

开始介绍

发现问题

看一份代码

 我们知道,当子进程出现写实拷贝的时候,将共享的数据拷贝一份,为子进程独立存储。

让我们运行该代码。

分析结果:1、写实拷贝前:在写实拷贝前子进程与父进程的flag数据相同,数据地址相同,无可厚非为写时拷贝前,父子进程共享一块数据空间

                 2、写实拷贝:子进程准备修改flag数据,先发生写实拷贝-父进程的flag数据拷贝一份,然后拷贝的空间给子进程形成独立,然后子进程的数据flag改变为222。

                 3、写实拷贝后,我们观察结果:子进程与父进程的flag值确实发生了不一样了,但是!!我们惊奇的发现他们的地址居然一模一样!同一个地址怎么能保存不一样的值呢??

                得出结论,我们看见的地址,其实并不是直接物理内存上面的地址,这里我们看见的地址其实是进程进程地址空间(虚拟地址)。

进程地址空间(虚拟地址)

我们常见这个表其实是不是内存上面的数据区分布,其实是进程空间分布图。它其实一种结构体类型。

让我们讲个小故事更加了解虚拟内存:

        有一个有钱的富翁他对他的朋友非常的好,但是他的朋友们都不知道富翁有其他朋友,以为富翁只有他一个朋友,富翁有一千万元,他对所有朋友说哎呀我的钱都可以借给你,但是你不能一下子借太多,要经过我的同意才行。富翁所有的朋友都认为自己可以向富翁借款一千万,所有他们就先规划了这一千万怎么用。富翁也可以同时放贷给许多朋友。故事先暂停一下。

        这里的富翁换成物理内存,而朋友们换成进程,所有的进程都是独立的其实,但是进程都认为一个人独占了整个物理内存资源,所以就事先规划了内存使用的分布。划分了并不代表拥有,只是划分了而已

        这里我们介绍一下inux的进程地址空间:struct mm_struct{}  这个结构体就是进程地址空间结构体

        这里的每对数据其实就是对应着每个段的开始和结束。

但是单单只有进程地址空间也没办法,毕竟所有的进程都认为自己独占了物理内存,所以必须加上一些东西-->页表+查叶表。

页表

查页表:也就是在页表上查询数据一个硬件设施(这里我们不做过度说明)

页表:Linux在启动过程中,要首先进行内存的初始化,那么就一定要首先创建页表。我们知道每个进程都拥有各自的进程空间,而每个进程空间又分为内核空间和用户空间。
以32位计算机为例,每个进程有4G的虚拟空间,其中0-3G属于用户地址空间,3G-4G属于内核地址空间,内核地址空间是所有进程共享的,因此内核地址空间的页表也是所有进程共享的。

Linux内核中用户进程内存页表的管理是通过一个结构体mm_struct来描述的  

让我们抽象的描述页表

 左边是进程地址空间,而右边是物理地址空间,页表是承接进程地址空间与物理地址空间的桥梁。

接下来我们将物理内存、页表、进程地址空间建立一个初步的了解:

物理内存与进程地址空间映射

举个例子:现在我们进程中main函数地址我们需要存在物理内存中先将main虚拟地址传入页表进程空间列

 然后在操作系统将该进程main函数真实地址与对应虚拟地址对应。

 这样当我们需要访问main时的时候我们的操作系统就会让cpu根据该进程的页表映射关系找到实际的函数代码入口。

小知识点,为了让cpu快速在虚拟地址访问到进程入口处,我们无论是哪个进程的main函数地址都是一样的。

观察进程pid:两个不同进程加载到了内存,但是他们的main函数地址居然时相同的,发现虽然进程不同当时main函数入口是相同的,然后再从与对应的物理内存实际映射找到物理内存上该进程main实际的地址:我们的

继续观察

 

让我们同时运行程序 

两份代码同时加载在进程,同时为R状态,但是他们的main地址居然相同,有一次的告诉我们我们取得main函数地址为虚拟地址。这些进程都有自己的PCB,mm_struct、页表,所有他们访问内存实际其实是,通过映射关系访问,而不是直接去内存访问数据

 各访问各的。

 缺页中断基本概念

个人理解:缺页中断就是操作系统先暂停对进程通过页表访问物理内存,然后操作系统对物理内存进行操作(拷贝父进程数据(写实拷贝),申请动态内存空间),然后再让进程操作该空间数据

我们先写份代码:

#include<iostream>
#include<unistd,h>
int main()
{int*p=new int[10];*p=10086;*(p+1)=10087;*(p+2)=10088;return 0;
}

我们向内存申请40各字节的空间。确实现在空间的使用全给我了。但是我并没有立刻使用空间,而是过了10秒才使用。如果这个空间一直等待我我写入数据的话,大大的浪费了内存的使用效率。所有操作系统会先让急需内存的进程先使用空间,当我需要写入的时候,再去给我开辟空间。

画图理解:

第一步先去申请空间:我们在进程地址空间查看是可以开辟40各字节的空间,允许开辟,然后返回空间地址值,这里我们这里申请的是虚拟地址空间,然后反馈告诉进程,申请空间成功。(其实并没有在物理内存中申请)。

 第二,我们进程进入休眠状态,如果我们申请的是物理内存,那么这10秒我们申请的物理内存就要一直等待被当前进程使用,现在我们申请的只是虚拟内存,这并不占用物理内存40个字节,这样这40个字节空间可以被其他的进程先使用

 当10秒过去后,我们cpu运行当前进程,需要写入数据,这时不会立刻写入数据而是,先发生中断,也叫做缺页中断。操作系统先去物理内存申请40个字节空间然后与该进程建立映射关系,然后才将数据写入空间(这里写一份可能就开辟4个字节空间,还有36字节空间不会开辟,未学习地方,以后回来补充)。

看步骤

 休眠结束当我们需要在这块空间写入空间,先暂停写入

 I:操作系统先在物理内存开辟空间。

 

II:将开辟的空间与进程地址空间建立映射关系(操作会进行到访问进程)

 

 III、最后通过映射关系,在物理地址上写入数据

 全图:

并不是所有的地址都映射在页表上: 

 如果是这样,4G物理内存只能跑一个进程甚至一个都跑不了。一页项有物理内存与虚拟内存,不止要4g空间。

所有页表也是按需申请页表项的。

写时拷贝的原理(基于缺页中断)

运行这段代码得到结果,我们知道发生了写实拷贝

让我们看看怎么回事

 首先:这是父进程的进程信息,val存放在虚拟地址数据区,映射在物理内存上为0x00afcd。

发生创建子进程,其实就是将PCB、mm_struct、页表拷贝一份给子进程,那么还没写实拷贝前,其实所有的数据都是和父进程一模一样的。就是直接拷贝一份父进程数据给子进程。创建子进程时,将父进程的 虚拟内存 与 物理内存 映射关系复制到子进程中,并将内存设置为只读(设置为只读是为了当对内存进行写操作时触发 缺页异常)。

他们所有数据都是一样的,映射关系也是相同的。

        当我们想要改变子进程的val值会发生写实拷贝。发现该数据为在页表项为只读发生缺页中断,拷贝该物理空间数据,将映射关系改为映射拷贝的物理内存数据。

 

 这里改变子进程页表的val权限,不会影响父进程的val权限,防止父进程创建多个子进程而导致无法发生缺页中断。

如果父进程发生写实拷贝呢?那么就是父进程改变映射关系,映射到拷贝的空间上,权限为可读可写,而原空间可能依旧有多个进程正在使用,所以原空间权限不变,不受到父进程的影响


谢谢阅读,如有错误请大佬留言!!


http://www.ppmy.cn/news/57343.html

相关文章

LidarMultiNet:在单个多任务网络中统一LiDAR语义分割、三维目标检测和全景分割

Abstract 这份技术报告介绍了2022年Waymo开放数据集3D语义分割挑战赛的第一名获奖解决方案。我们的网络称为LidarMultiNet,将主要的LiDAR感知任务(例如3D语义分割、目标检测和全景分割)统一在一个框架中。 LidarMultiNet的核心是一个强大的基于3D体素的编码器-解码器网络,…

Fiddler抓包工具常见功能介绍,还不会的进来看

目录 Fiddler的功能面板 一、Statistics数据统计面板&#xff0c;性能分析 二、Inspectors查看请求与响应 三、Filters过滤器 1、User Filters启用 2、Action 3、过滤器实际应用 四、AutoResponder请求重定向 1、什么是请求重定向&#xff1f; 2、为什么要用这个功能&…

CleanMyMac X4.13.2最新版下载

现在cleanmymac x4.13.2中文版是大家首选的优秀mac清理软件。CleanMyMac集合了多种功能&#xff0c;几乎可以满足用户所有的清洁需求。它不仅包含各种清理功能&#xff0c;还具有卸载、维护、扩展、碎纸机等实用功能&#xff0c;可同时替代多种工具。它可以清理、优化、维护和监…

three.js进阶之动画系统

我曾在three.js进阶之骨骼绑定文章中提到了AnimationMixer、AnimationAction等内容&#xff0c;其实这些应该属于Three.js的动画系统&#xff0c;本文就系统的介绍一下动画系统&#xff08;Animation System&#xff09;。 前言 一般情况下&#xff0c;我们很少会使用three.j…

[Eigen中文文档] 编译器对堆栈对齐做出了错误的假设

文档总目录 本文目录 局部解决方案全局解决方案 英文原文(Compiler making a wrong assumption on stack alignment) 这是 GCC 的错误&#xff0c;已在 GCC 4.5 中修复。如果遇到此问题&#xff0c;请升级到 GCC 4.5 。 到目前为止&#xff0c;我们只在 Windows 上遇到过 GC…

【Unity-UGUI控件全面解析】| Text文本组件详解

🎬【Unity-UGUI控件全面解析】| Text文本组件详解一、组件介绍二、组件属性面板三、代码操作组件四、组件常用方法示例4.1 改变Text文本颜色4.2 文本换行问题4.3 空格自动换行问题4.4 逐字显示效果五、组件相关扩展使用5.1 文本描边组件(Outline)5.2 阴影组件(Shadow)5.3…

Java每日一练(20230503)

1. 外观数列 给定一个正整数 n &#xff0c;输出外观数列的第 n 项。 「外观数列」是一个整数序列&#xff0c;从数字 1 开始&#xff0c;序列中的每一项都是对前一项的描述。 你可以将其视作是由递归公式定义的数字字符串序列&#xff1a; countAndSay(1) "1"c…

【Linux从入门到精通】vim的基本使用各种操作详解

文章目录 一、vim编辑器简单介绍 二、vim编辑器的四种模式 2、1 正常/普通/命令模式(Normal mode) 2、2 插入模式(Insert mode) 2、3 末行模式(last line mode) 三、命令模式的相关操作实例 3、1 光标的相关操作 3、2 文本操作 四、插入模式下的相关操作 五、末行模式下的相关操…