【操作系统导论】内存篇——分页

引入

采用 「分段」 的方式,将空间切成 不同长度的分片,会出现 碎片化 问题,随着时间推移,分配内存会越来越困难。

因此,值得考虑「分页」的方法:

  • 将空间分割成 固定长度的分片

  • 将物理内存看成是定长槽块的阵列,叫作 页帧 (page frame,PF),每个页帧包含一个虚拟内存页。

「分页」具有许多优点:

  • 灵活性

    通过完善的分页方法,操作系统能够高效地提供地址空间的抽象,不管进程如何使用地址空间。

    例如,不用假定「堆」和「栈」的增长方向,以及它们如何使用。

  • 简单性

    假设有一个 64 字节的地址空间,且一个页帧为 16 字节,则只需要在物理地址空间中找到 4 个空闲页。

线性页表

地址转换

为了实现地址转换,需要将虚拟地址看作两个部分:*虚拟页面号(VPN)*和 页内偏移量(offset)

假设进程的虚拟地址空间是 64 字节,页帧大小为 16 字节:

  • 页帧大小 16 字节,对应 2 的 4 次方,则 offset 占 4 位;

  • 地址空间 64 字节,对应 2 的 6 次方,则 VPN 占 2 位。

在这里插入图片描述

转换虚拟地址,只需要将*「虚拟页面号 VPN」替换成「页帧号 PFN」*。

在这里插入图片描述

页表结构

为了记录地址空间的虚拟页在物理内存中的位置,OS 为每个进程保存一个数据结构,称为 页表(page table)

页表不由硬件存储,它通常存放在内存中,甚至可以被交换到磁盘上。

对于下面例子,页表中应该具有 4 个条目:(VP 0 → PF 3)、(VP 1 → PF 7)、(VP 2 → PF 5)、(VP 3 → PF 2) 。

在这里插入图片描述

那么,页表的结构究竟是怎么样的呢?

最简单的形式为 线性页表(linear page table),即一个数组。

操作系统通过「虚拟页面号 VPN」检索该数组,在索引处查找**「页表项 PTE」**,再找到对应的「页帧号 PFN」。

对于一个「页表项 PTE」,具有着许多的位,比如:

  • 有效位(valid bit)

    用于指示特定的地址转换是否有效。

    通过将地址空间中所有未使用的页面标记为无效,则不再需要为这些页面分配物理帧,从而节省大量内存;

    如果进程尝试访问这部分无效空间,就会陷入操作系统,可能会导致进程终止。

  • 保护位(protection bit)

    表明该页是否可以读取、写入、执行。

    同样,以不被允许的方式访问该页,则会陷入操作系统。

  • 存在位(present bit)

    表明该页是在物理内存中还是在磁盘上。

  • 访问位(accessed bit)

    用于追踪页是否被访问,也用于确定哪些页比较受欢迎,应该保留在内存中。

  • 脏位(dirty bit)

    表明该页被带入内存后是否被修改过。

下面是 x86 架构的页表项:

包含了存在位(P),读/写位(R/W),用户/超级用户位(U/S),访问位(A),脏位(D);

(PWT、PCD、PAT 和 G)用来确定硬件缓存如何为这些页面工作,最后是页帧号(PFN)。

在这里插入图片描述

可以阅读「英特尔架构手册」,以获取有关 x86 分页支持的更多详细信息。

硬件 TLB

对于每个内存引用(取指令、显式加载、存储),分页需要执行一个额外的内存引用,以便从页表中获取地址转换。

这使得 额外的内存引用开销大,在这种情况下,可能会导致 系统运行速度减慢两倍或更多

想要加速虚拟地址转换,自然要借助硬件的帮忙,即 地址转换旁路缓冲存储器(TLB),简称 地址转换缓冲

对每次内存访问,硬件先检查 TLB 中是否有期望的转换映射,如果没有,再访问页表。

TLB 带来了巨大的性能提升,实际上,因此它使得虚拟内存成为可能。

基本算法

现在假定使用「线性页表」和硬件管理的「TLB」,则算法的大体流程如下:

// get VPN
VPN = (VirtualAddress & VPN_MASK) >> SHIFT

// look up TLB
(Success, TlbEntry) = TLB_Lookup(VPN)

if (Success == True)     // TLB Hit 
{
    if (CanAccess(TlbEntry.ProtectBits) == True) 
    {
        Offset = VirtualAddress & OFFSET_MASK
        PhysAddr = (TlbEntry.PFN << SHIFT) | Offset    // get physical address from TLB
        AccessMemory(PhysAddr)                         // access physical memory
    }
    else 
    {
        RaiseException(PROTECTION_FAULT) 
    }
}
else                     // TLB Miss                  
{
    PTEAddr = PTBR + (VPN * sizeof(PTE))       // get PTE address
    PTE = AccessMemory(PTEAddr)                // get PTE
    if (PTE.Valid == False) 
    {
        RaiseException(SEGMENTATION_FAULT) 
    }
    else if (CanAccess(PTE.ProtectBits) == False) 
    {
        RaiseException(PROTECTION_FAULT) 
    }
    else 
    {
        TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits)    // renew TLB
        RetryInstruction()                           // retry this instruction
    }
}

补充:TLB 未命中的情况,可能由硬件处理,也可能由软件(操作系统)处理。

假设有一个 8 位的虚拟地址空间,页帧大小为 16 字节,虚拟地址划分为 4 位的 VPN 和 4 位的 offset;

现在,我们要遍历一个整型数组 a[10],它在地址空间中的分布如下:

在这里插入图片描述

在访问元素 a[0]a[3]a[7] 时,TLB 会出现「未命中」的情况,整体的命中率为 70%。

对于典型的 4KB 大小的页来说,这种密集的数组访问会实现极好的 TLB 性能,每个页的访问只有一次「未命中」。

TLB 结构

典型的 TLB 有 32 项、64 项、128 项,并且是全相联的(fully associative)。

基本上,这就意味着一条地址映射可能存在 TLB 中的任意位置,硬件会并行地查找 TLB,找到期望的转换映射。

一条 TLB 项的结构:[ VPN | PFN | 其他位 ]

TLB 项中可能包括以下位:

  • 有效位(valid bit)

    表明该 TLB 项是不是有效的地址映射。

  • 保护位(protection bit)

    表明该页是否可以读取、写入、执行。

  • 脏位(dirty bit)

    表明该页被带入内存后是否被修改过。

  • 全局位(Global bit)

    表明该页是不是所有进程全局共享的。

  • 地址空间标识符(ASID)

    用于区分不同的地址空间,ASID 位的引入允许 TLB 维护多个地址空间的映射。

管理 TLB

首先,在进行上下文切换时,TLB 会面临一些问题。

假设进程 P1 在 TLB 中缓存了有效的地址映射:VPN 10 → PFN 100;

操作系统进行上下文切换,运行进程 P2,P2 也在 TLB 中缓存一条地址映射:VPN 10 → PFN 170;

那么,在上下文切换时,如何管理 TLB 的内容?

  1. **清空 TLB:**将所有项的有效位(valid)置为 0

这是可行的解决方案,进程不会读到错误的地址映射;

每次切换进程后,访问数据和页,都会触发 TLB 未命中;如果 OS 频繁切换进程,产生的开销很高。

  1. **添加 ASID:**区分不同的地址空间

如前面讲到的,ASID 使得 TLB 可以维护多个地址空间的映射。

在这里插入图片描述

还有一个问题:在向 TLB 添加新项时,应该替换哪个旧项?

  1. 最近最少使用

LRU 算法利用了内存引用流中的局部性,假定最近没有用过的项,可能是好的换出候选项。

  1. 随机策略

随机选择一项换出去,该策略不仅简单,并且可以避免一种极端情况:

程序循环访问 n+1 个页,但 TLB 只能存放 n 个页;该情况下,LRU 每次访问内存时都会触发 TLB 未命中。

多级页表

前面的讨论都是基于「线性页表」,但是*「线性页表」占用的内存很大* 。

假设一个 32 位地址空间,4KB 的页和一个 4B 的页表项;一个地址空间中大约有一百万个虚拟页面,乘以页表项的大小,则一个页表大小为 4MB。那么,一百个进程,就要占用数百兆的内存!

因此,要寻找新的技术来减轻这种沉重的负担,即:多级页表(multi-level page table)

基本思路

「多级页表」的思路如下:

  • 首先,将页表分成页大小的单元;

  • 通过 **页目录(page directory)**来追踪页表的页表项是否有效;

  • 如果在「页目录」中记录的页无效,则不为该页的页表分配内存。

以一个两级页表为例,**页目录项(Page Directory Entries,PDE)**中记录着一个 有效位页帧号 PFN

在这里插入图片描述

通过增加一个间接层「页目录」,我们可以将「页表的页单元」放在物理内存中的任何地方!

地址转换

现在,我们来构建一个二级页表。

假设有一个 16KB 的虚拟地址空间,页帧大小为 64 字节,虚拟地址划分为 8 位的 VPN 和 6 位的 offset;

那么,应该有 2 8 = 256 2^8=256 28=256个「页表项」,假设每个 PTE 的大小为 4 字节,则页表的大小为 1KB,占 16 个页帧。

我们将 VPN 的前 4 位划分为 页目录索引(PDIndex),剩余的位为 页表索引(PTIndex),如下所示:

在这里插入图片描述

  • PDEAddr = PageDirBase + (PDIndex * sizeof(PDE))

  • PTEAddr = (PDE.PFN << SHIFT) + (PTIndex * sizeof(PTE))

// get VPN
VPN = (VirtualAddress & VPN_MASK) >> SHIFT 

// look up TLB
(Success, TlbEntry) = TLB_Lookup(VPN) 
  
if (Success == True)   // TLB Hit 
{
    if (CanAccess(TlbEntry.ProtectBits) == True) 
    {
        Offset = VirtualAddress & OFFSET_MASK 
        PhysAddr = (TlbEntry.PFN << SHIFT) | Offset 
        Register = AccessMemory(PhysAddr)            // access physical memory
    }
    else
    {
        RaiseException(PROTECTION_FAULT) 
    }
}
else                   // TLB Miss 
{
    // first, get page directory entry 
    PDIndex = (VPN & PD_MASK) >> PD_SHIFT 
    PDEAddr = PDBR + (PDIndex * sizeof(PDE)) 
    PDE = AccessMemory(PDEAddr)                      // get PDE
    if (PDE.Valid == False) 
    {
        RaiseException(SEGMENTATION_FAULT) 
    }
    else 
    {
        // PDE is valid: now fetch PTE from page table 
        PTIndex = (VPN & PT_MASK) >> PT_SHIFT 
        PTEAddr = (PDE.PFN << SHIFT) + (PTIndex * sizeof(PTE)) 
        PTE = AccessMemory(PTEAddr)                  // get PTE
        if (PTE.Valid == False) 
        {
            RaiseException(SEGMENTATION_FAULT) 
        }
        else if (CanAccess(PTE.ProtectBits) == False) 
        {
            RaiseException(PROTECTION_FAULT) 
        }
        else 
        {
            TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits) 
            RetryInstruction()
        }
    }
}

时空折中

「多级页表」是有成本的。

当 TLB 未命中时,需要从内存加载两次(先访问页目录,后访问 PTE),才能从页表中获取正确的地址转换信息。

因此,「多级页表」是 时间—空间折中 的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中医电子处方管理系统软件,中医配方模板一键生成软件操作教程

一、前言&#xff1a; 在中医开电子处方时&#xff0c;如果能够使用配方模板功能&#xff0c;则可以节省很多时间。使用配方模板一键导入&#xff0c;几秒即可完成开单。 下面就以佳易王电子处方管理系统软件V17.1版本为例说明&#xff0c;其他版本可以参考&#xff0c;软件下…

场景的组织及渲染(一)

在OSG 中存在两棵树&#xff0c;即场景树和渲染树。场景树是一棵由 Node组成的树,这些Node可能是矩阵变换、状态切换或真正的可绘制对象&#xff0c;它反映了场景的空间结构&#xff0c;也反映了对象的状态。本章重点介绍场景树&#xff0c;在第 5章将会对渲染树作详细的介绍。…

GoWin FPGA, GPIO--- startup2

一个Bank只能用一个电压&#xff0c;假如同一个Bank&#xff0c;在引脚里设置不同的电压&#xff0c;编译不过。 解释说明 2. 错误引脚限制 以上编译设置会导致编译错误。

Docker | 发布镜像到镜像仓库

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏:Docker系列 ✨特色专栏: MySQL学习 🥭本文内容:Docker | 发布镜像到镜像仓库 📚个人知识库: [Leo知识库]https://gaoziman.gitee.io/bl…

std::vector

这里主要介绍下reserce/resize、push_back/emplace_back、shrink_to_fit/clear等接口&#xff1b; 1. reserve and resize C的vector对象可以通过reserve方法来设置vector对象的容量&#xff0c;通过resize方法来改变vector对象的大小。reserve所设置的容量指的是vector容器中可…

0基础学习VR全景平台篇第127篇:什么是VR全景/720全景漫游?

“全景”作为一种表现宽阔视野的手法&#xff0c;在很久之前就得到了普遍的认同。北宋年间&#xff0c;由张择端绘制的《清明上河图》就是一幅著名的全景画。摄影术出现后&#xff0c;全景摄影也随之而生。 到今天&#xff0c;全景拍摄不再被专业摄影师所独享&#xff0c;广大…

云计算与AI融合:Amazon Connect开创客户服务智能时代

授权说明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 在亚马逊云科技 re:Invent 2023 大会上&#xff0c;Amazon Connect…

[AutoSar]状态管理(四)单核BswM(二)流程、配置、 代码

目录 关键词平台说明一、BswM的模式处理流程图二、stand state handling三、配置、代码、状态转移3.1 initial -> wakeup   3.2 WakeUp -> Run3.3 Run -> PostRun &#xff08;first step&#xff09;3.4 Run -> PostRun &#xff08;second step&#xff09;3.5…

Python安装报错: This environment is externally managed

error: externally-managed-environment This environment is externally managed ╰─> To install Python packages system-wide, try apt installpython3-xyz, where xyz is the package you are trying toinstall.这个错误信息表示当前Python环境是由系统外部管理的&…

基于Docker-Compose实现ELK+Kafka搭建分布式日志采集系统

ELKKafka搭建日志采集系统 ELK概述搭建与配置docker-compose.yml配置日志采集规则启动服务 模拟发送日志消息日志发送队列日志切面配置application.yaml发送日志消息 Kibana的使用创建索引模式Discovery搜索数据可视化数据 ELKRabbitMQ发送日志消息配置日志采集规则 ELK概述 E…

Java IO 流详解

Java IO 流详解 1 .Java IO概念 Java IO&#xff1a;即 Java 输入 / 输出系统。 Java 的 IO 模型设计非常优秀&#xff0c;它使用 Decorator (装饰者)模式&#xff0c;按功能划分 Stream &#xff0c;您可以动态装配 这些 Stream &#xff0c;以便获得您需要的功能。 Stream &…

20 Redis进阶 - 运维监控

1、理解Redis监控 Redis运维和监控的意义不言而喻&#xff0c;可以以下三个方面入手 1.首先是Redis自身提供了哪些状态信息&#xff0c;以及有哪些常见的命令可以获取Redis的监控信息; 2.一些常见的UI工具可以可视化的监控Redis; 3.理解Redis的监控体系;2、Redis自身状态及命…

【Java反射详解】

Java反射详解 &#x1f38a;专栏【Java】 &#x1f354;喜欢的诗句&#xff1a;关山难越&#xff0c;谁悲失路之人。 萍水相逢&#xff0c;尽是他乡之客。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出问题&#x1f970; 1.什么是反射 所谓的反射就是java…

365锦鲤助手 砍价小程序源码 流量主引流裂变

源码介绍 修改版365锦鲤 助手&#xff0c; 砍价小程序源码 流量主引流裂变 拼多多商品快速丰富产品内容满足广大用户需求&#xff1b;流量矩阵让流量都进你的圈子飞起来&#xff1b;长期盈利、项目稳定 1.后台安装微擎 2安装应用 后台打包上传

PPINN Parareal physics-informed neural network for time-dependent PDEs

论文阅读&#xff1a;PPINN Parareal physics-informed neural network for time-dependent PDEs PPINN Parareal physics-informed neural network for time-dependent PDEs简介方法PPINN加速分析 实验确定性常微分方程随机常微分方程Burgers 方程扩散反应方程 总结 PPINN Par…

Npm安装vue3报错(node:25436) MaxListenersExceededWarning:

运行命令安装vue3时 npm create vuelatest 报了错误(node:25436) MaxListenersExceededWarning: (忘记截报错的图了&#xff0c;后面还有一大串英文) 搞了很久发现是网络的原因&#xff0c;我没有修改镜像地址&#xff0c;导致访问很慢&#xff0c;于是去npmmirror 镜像站 …

字符雨canvas

整体思路&#xff1a; 确定好字符雨的具体字符是什么&#xff0c;需要多少行多少列这里是写死的其实也可以用循环加随机的方式生成不一样的字符雨&#xff0c;行列也可以读一下宽度然后做一下出发算一下也行首先得有一张画布搞起&#xff0c;然后循环列数去绘画字符定时器循环…

泰森多边形半平面求交 - 洛谷 - P3297 [SDOI2013] 逃考

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 往期相关背景半平面求交 点击前往 voronoi 图求解点击前往 题目大意 题目链接 https://www.luogu.com.cn/problem/P3297 小杨家是一个矩阵&#xff0c;所有亲戚都在…

Monkey工具之fastbot-iOS实践

背景 目前移动端App上线后 crash 率比较高&#xff0c; 尤其在iOS端。我们需要一款Monkey工具测试App的稳定性&#xff0c;更早的发现crash问题并修复。 去年移动开发者大会上有参加 fastbot 的分享&#xff0c;所以很自然的就想到Fastbot工具。 Fastbot-iOS安装配置 准备工…

变电站蓄电池在线监测系统(论文+源码)

1. 系统设计 本次课题为变电站蓄电池在线监测系统的设计&#xff0c;其系统架构如图3.1所示&#xff0c;包括了主控制器STC89C52单片机&#xff0c;液晶显示器LCD1602,模数转换器ADC0832&#xff0c;电流传感器ACS712&#xff0c;分压电阻&#xff0c;蜂鸣器以及温度传感器。在…