【程序地址空间】页表的映射方式

文章目录

前言

本片文章我们主要介绍页表的映射方式,通过学习页表的映射方式深入理解程序地址空间的概念,创作不易,如果觉得本篇文章写的还不错的话希望留下点赞、关注加转发,您的支持就是我创作的最大动力

什么是线程

在谈论线程的概念之前,我想先带领大家一起回顾什么是进程:

  • 进程就是一个运行起来的执行流,一个被加载到内存中的程序,同时进程等于内核数据结构加上自己的代码和数据
  • 对于一个操作系统而言,创建进程是一个成本比较高的事情,比如创建进程我们要创建进程的地址空间、创建虚拟地址和物理地址的映射关系、维护进程的信号、维护标准输出标准错误、维护与进程相关的文件、加载对应的代码和数据、进行缺页中断、写时拷贝等技术
  • 进程是操作系统分配资源的基本单位

为了解决进程占据操作系统资源较多的这一问题,线程应运而生,那么什么是线程呢?

  • 在操作系统当中,我们一般把线程叫做一个进程内部的一个执行流,更轻量化
  • 线程是CPU调度的基本单位

那么我们讲了上面关于线程的概念,相信大家是没有办法理解,为了帮助大家理解,我想先和大家一起探讨一下地址空间这个概念

程序地址空间------页表如何映射

页表是什么

我们知道,页表是虚拟地址到物理地址映射的桥梁,是一种内核的数据结构,也要在内核当中存在,也要占据物理内存,那么此时我们有一个问题,页表构建的映射关系是按照字节映射的吗?

对于上面的问题,我们目前知道的一个结论是:字节是内存访问的基本单位;虚拟地址空间是从0X000...000到0Xffff...fff,每一个地址都对应一个字节,所以我们此时可以猜测,页表构建的映射关系是按照字节来映射的。那么这个解释是正确的吗?我们此时打一个大大的问号,继续向下面分析

此时我们举一个例子:假设我们虚拟地址占四个字节,物理地址也占四个字节,一个页表项就是8字节,如果我们按照4GB的虚拟地址空间去算,那么4GB就存在4x1024x1024x1024个地址,如果我们通过页表进行映射,那么页表就需要8x4x1024x1024x1024字节,约合32GB大小的空间,这里还只是算了一个进程的一个虚拟地址空间的大小,那么很显然,这样的映射关系是不可能的,所以此时我们就可以回答上面的问题:页表并不是按照字节为单位进行映射的

那页表应该怎么进行映射呢?为了回答这个问题,我想先带领大家一起回顾一下物理内存和磁盘的关系

在文件系统层面上,物理内存和磁盘进行IO时的基本单位4KB(大部分情况下),对于磁盘的文件系统而言,不论是inode还是文件的内容,最终在保存这个文件的时候都是按照4KB为单位进行保存的,所以磁盘被划分成了许多个数据块,每一个数据块的大小都是4KB,且都有一个地址叫做块地址,块地址最终可以转换成LBA地址,将LBA地址给CPU,CPU转换成CHS地址就可以对磁盘进行访问了

在逻辑上,物理内存实际上也被划分成了4KB所对应的空间,所谓的文件系统本质就是把磁盘上的4KB内容选择一个物理内存上的磁盘空间并载入进去,而这一过程叫做文件系统的IO,同时我们将物理内存当中的数据刷新到磁盘上去的时候,是将4KB的内容作为整体刷新到磁盘上指定的位置,当我们有了这个认识,我们就可以在逻辑上把抽象出来的4KB物理内存块叫做页框/页帧,所以我们在进行磁盘IO的时候无非是一个提供内容一个提供存储空间,所以物理内存和磁盘都叫做存储介质,因为它们都可以作为彼此的数据源,也可以作为彼此的空间

那么我们该如何理解页框的概念呢?

从操作系统的视角上看,物理内存上面的每一个页框有些是正在被使用的、有些是空的、有些是正在被释放的、有的页框保存的是缓存数据正在被刷新等等状况,总之物理内存上面的每一个页框在同时被我们的系统使用的时候,不同的页框就会保持不同的状态,将来还会有不同的进程会向操作系统申请和释放页框,所以操作系统需要管理这些页框,那么应该如何管理这些页框呢?答案是先描述再组织

所以在操作系统内部就会存在一个描述页框page的结构体,每一个物理内存页都会在操作系统内部存在一个struct page的数据结构,用来描述我们当前page的使用情况;那么我们该怎么将这些page结构体组织起来呢?实际上我们可以用一个结构体数组来统一管理这些page,所以在操作系统里面存在一个大的结构体数组,通过这个大数组将所有的page管理起来,此时我们就将对整个物理内存的管理转化成了对数组的增删查改,因此我们就可以将数组0下标的位置与第一个物理内存块对应;数组1下标的位置与第二个物理内存块对应,以此类推,那么物理块的起始地址等于数组下标乘以4KB,所以你要申请一个内存块,本质是你要找到struct page对应的下标,那么物理内存的所有地址就全都有了,申请所谓的内存本质是在数组当中申请一个struct page结构

那么此时我们就可以大致知道虚拟地址如何转换到物理地址,这个过程大致就是虚拟地址通过页表映射找到page数组,通过page数组找到物理page的起始位置,并与之建立映射关系

页表是什么样子?虚拟地址如何与物理地址进行转换?

我们这里直接用别人画好的一张页表映射图进行理解:

在CPU当中存在一个EIP指令寄存器,表示当前正在执行指令的下一条指令的地址,而进入到CPU当中的地址都叫做虚拟地址,在CPU当中会存在一个CR3寄存器,这个寄存器会保存当前正在执行的进程的页表,32位系统里面的页表是二级页表,二级页表的第一张页表叫做页目录,一共有1024个页表项,第二级页表叫做真正的页表,而页目录里面页表项存放的是下一级页表所对应的起始地址,从虚拟地址转化到物理地址默认是没有转化到字节的,查页表的过程只是帮助我们找到了我们要访问的物理内存的哪一个页框

在编译器编译代码,给可执行程序分配内存时,虚拟地址被划分成了三部分分别是10个比特位、10个比特位、12个比特位,当进程的pcb在调度当前进程需要虚拟转物理时,会拿着第一部分的前十个比特位索引第一张页表,直接映射到要查的哪一张映射表,再拿着虚拟地址的中间十位作为虚拟地址的下标索引第二张页表,找到对应页表项中保存的物理页起始地址,得到页框的起始地址,最后拿着虚拟地址的低十二位做业内偏移,真正的物理地址=页框起始地址+页内偏移,而页框的起始位置就是查表得到的,通过页内偏移就可以访问到任意一个物理内存以字节为单位的空间了,之所以页内偏移要用12个比特位是因为2^12=4KB

细节:

  • cr3寄存器里面保存的是页表的基地址,物理地址
  • 虚拟地址的划分编译器不参与
  • 高20相同的地址一定是连续存放在一个页框的,相同属性的代码或者数据,在一个4kb块里面
  • 如果我知道任意一个虚拟地址,只需要让虚拟地址&1111 1111 1111 1111 1111 0000 0000 0000就的到了对应的页框,而页框号/4kb就得到了page数组的下标,就可以去访问到虚拟地址
  • 进程首次加载磁盘块的时候,操作系统会进行内存管理先申请内存,再申请page的到page所对应的下标,然后就可以得到对应的页框物理地址,填充页表
  • 如果我们访问的是一个int、结构体、数组、类变量,这些变量都只有一个地址,这个地址就是开辟空间的最小字节的地址,页表转换的时候,只能拿到第一个字节的地址,所以语言中存在一个叫做类型的概念,类型就是偏移量
  • 操作系统内申请和管理内存是以4KB为单位的,而写时拷贝也是以4KB为单位的
  • 我们用new、malloc申请内存空间是按照字节申请的,而在底层一定要调用brk、mmap系统调用,而这些系统调用是有成本的,C/C++在语言层会有自己的内存管理机制,类似STL的空间配置器,比如我们申请6字节空间,实际上操作系统申请了8字节的空间,多申请的空间是由操作系统为我们管理起来的
相关推荐
序属秋秋秋2 小时前
《Linux系统编程之进程控制》【进程替换】
linux·c语言·c++·操作系统·进程·系统编程·进程替换
Mintopia2 小时前
🧠 从零开始:纯手写一个支持流式 JSON 解析的 React Renderer
前端·数据结构·react.js
hslinux2 小时前
NDK 通过configure 编译C++源码通用脚本
android·c++·ndk·configure
盖世灬英雄z2 小时前
数据结构与算法学习(二)
c++·学习
qq_310658512 小时前
webrtc源码走读(三)核心引擎层——音频引擎
服务器·c++·音视频·webrtc
UID96222 小时前
[特殊字符] 无级变速传动(CVT)技术突破之道 | 易经×数学×工程的跨维度破解方案
算法·数学建模·开源
嵌入式@秋刀鱼2 小时前
ROS开发学习记录【一】
linux·c++·笔记·学习
生信碱移2 小时前
神经网络单细胞预后分析:这个方法直接把 TCGA 预后模型那一套迁移到单细胞与空转数据上了!竟然还能做模拟敲除与预后靶点筛选?!
人工智能·深度学习·神经网络·算法·机器学习·数据挖掘·数据分析
吃西瓜的年年2 小时前
5.C语言流程控制语句
c语言·开发语言