【Chapter7】虚拟存储系统,计算机操作系统教程,第四版,左万利,王英

文章目录

    • @[toc]
    • 零、前言
    • 一、外存资源管理
      • 1.1 外存空间划分
      • 1.2 外存空间分配
        • 1.2.1 空闲块链(慢)
        • 1.2.2 空闲块表(UNIX)
        • 1.2.3 字位映像图
      • 1.3 进程与外存对应关系
    • 二、虚拟页式存储系统
      • 2.1 基本原理
      • 2.2 内存页框分配策略
      • 2.3 外存块的分配策略
      • 2.4 页面调入时机
      • 2.5 置换算法
        • 2.5.1 最佳淘汰算法
        • 2.5.2 先进先出
        • 2.5.3 最近最少使用(LRU)
        • 2.5.4 最近不用的先淘汰
        • 2.5.5 最不经常使用的先淘汰(LFU)
        • 2.5.6 最频繁使用算法
        • 2.5.7 二次机会
        • 2.5.8 时钟算法
        • 2.5.9 改进的时钟算法
      • 2.6 颠簸的概念
      • 2.7 工作集模型(working set model)
      • 2.8 页故障率反馈模型
    • 三、虚拟段式存储系统
      • 3.1 基本原理
      • 3.2 段的动态连接
        • 3.2.1 为什么要有动态连接
        • 3.2.2 动态连接的实现(Multics 为例)
        • 3.2.3 动态连接的问题
    • 四、虚拟段页式管理
      • 4.1 基本原理
      • 4.2 各种虚拟存储管理系统特性比较

零、前言

为何要有虚拟内存的概念?

我们已经学习了段页式存储管理,以及静态动态分配的策略,似乎已经可以很好的管理操作系统的内存空间。

然而我们平时游玩一些大型游戏,特别是场景较为精细的一些游戏如2077、大表哥2等,如此庞大的场景建模渲染,以及游戏业务逻辑的运行程序,显然大多数的电脑配置,哪怕是4090Ti实际上内存是不足以一次性将整个程序全部装入内存的。

所以我们发现,我们前面的内存管理方式似乎并不能满足实际中的很多需求,那么就有了虚拟内存的概念。

这其实是基于局部性原理,对于一个程序而言,其运行的任一阶段实际上只占用了内存空间的一部分罢了,以原神为例,我们没必要在枫丹游玩的时候把其它所有国家的场景建模加载进来。

所以虚拟存储其实就是一种借助外存空间,允许一个程序在其运行过程中部分装入的技术。

大致分为:虚拟页式、虚拟段式以及虚拟段页式。

一、外存资源管理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外存空间是指磁盘等存储型设备上的存储区域,在逻辑上可分为四个主要部分:输入井、输出井、文件空间、交换空间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.1 外存空间划分

外存空间被看成**物理块(block)**的有序序列。

块的大小通常为静态等长 2 i 2^i 2iB, 为一块。

块是外存分配的基本单位,也是IO传输的基本单位。

1.2 外存空间分配

1.2.1 空闲块链(慢)

空闲块链(和空闲页链相似),所有空闲块连成一条链,操作系统保存着链头链尾指针。

1.2.2 空闲块表(UNIX)

表目包含两个栏目:首空闲块号空闲块数,适用于记录连续的空闲块。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.2.3 字位映像图

位图(bitset),用1位来代表一个块的状态。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3 进程与外存对应关系

1、界地址存储管理外存空间分配

  • 交换技术可将进程交换到外存,此时一个进程占有若干个连续的外存块
  • 双对界技术:进程占据两个区域:一个保存代码一个保存数据

2、页式存储管理外存空间分配

  • 就是内存和外存进行交换的,内存一页,外存一块
  • 进程在外存储器占据若干块,这些块可以不连续

3、段式存储管理外存空间分配

占有若干个连续的外存块,进程多个段在外存储器可以不连续。

4、段页式存储管理外存空间分配

段内多页对应外存块可以不连续,一个进程的多段可以分散在外存储器的不同区域。

二、虚拟页式存储系统

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

无虚拟存储的问题

  • 不能运行比内存大的程序
  • 进程全部装入内存,浪费空间(进程活动具有局部性)
    • 单控制流的进程需要较少部分在内存
    • 多控制流的进程需要较多部分在内存

虚拟存储

  • 进程部分装入内存,部分(或全部)装入外存,运行时访问在外存部分动态调入,内存不够淘汰。

想要实现的事情:

  • 让内存空间和外存**“一样大”**
  • 访问外存的速度“逼近”访问内存的速度

2.1 基本原理

**进程运行前:**全部装入外存,部分装入内存。

进程运行时:

  • 访问页不在内存,发生缺页中断,中断处理程序
    • 找到访间页在外存的地址
    • 在内存找一空闲页面
      • 如没有,按淘汰算法淘汰一个
      • 如需要,将淘汰页面写回外存,修改页表和总页表
    • 读入所需页面(切换进程)
    • 重新启动被中断的指令

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为实现虚拟页式管理,我们需要在页表增加一下栏目

  • 外存块号,内外标志,修改标志等
    在这里插入图片描述

2.2 内存页框分配策略

如何将内存页框分配给诸进程呢?

1、平均分配

平均分配:将内存中的所有物理页面等分给进入系统中的进程。

如:内存中的物理页面数为93,进程数为5,则每个进程分得18个物理页面剩余3个页面。

2、按进程长度比例分配

即按程序长度的比例确定分配内存物理页面数。

S为总页面数,ai为进程Pi的分配页面数:
S = ∑ s i , a i = ( s i / S ) × m \begin{align} & S=\sum s_i , a_i = (s_i / S) \times m \end{align} S=si,ai=(si/S)×m

3、按进程优先级比例分配

类似于按进程长度比例分配,我们也可以按照进程优先级比例分配

4、按进程长度和优先级别比例分配

将方法2、3结合,即将2中的si替换为进程Pi的逻辑页面数和优先级之和。

四种方法都是静态的分配策略,没有考虑页面的动态行为特性,且进程在不同的执行阶段对页面局部性也是变化的。

2.3 外存块的分配策略

1.静态分配

外存保存进程的全部页面

  • 一个进程在运行之前,将其所有页面全部装入外存储器。当某一外存页面被调入内存时所占用的外存页面并不释放。

优点:

  • 速度快,淘汰时如果未修改则不必写回外存

缺点:

  • 牺牲一定的外存空间

2.动态分配

外存仅保持进程不在内存的页面

优点

  • 节省外存

缺点

  • 速度慢,淘汰时必须写回

2.4 页面调入时机

1、请调

请调(demand paging,也称请求分页),当发生缺页故障时,操作系统将其动态调入内存。

2、预调

预调(pre-paging),即一个页面访问之前就将其调入内存。

预调不一定准确,所以还是要用请调辅助。

2.5 置换算法

置换算法(replacement algorithm)又称淘汰算法、替换算法,用于确定页面的调出原则。

置换算法的设计既要考虑效果,又要考虑开销。

用途:页淘汰,段淘汰,快表淘汰。

2.5.1 最佳淘汰算法

最佳淘汰算法(OPT-optimal)本质是贪心算法,即淘汰以后不再需要的或者在最长时间以后才会用到的页面

个人喜欢叫他预言家算法

我们无法预知未来的页面访问情况,所以这个算法是无法实现的,但是我们有必要确定一个最理想的算法是怎样的

比如下面的例子,我们访问2的时候必须要淘汰掉一页,我们发现7号页面的下次访问时间最晚,所以我们淘汰了内存块1(7号页面)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.5.2 先进先出

老朋友了,思想就是淘汰遵循先进先出(FIFO)。每次替换都替换掉队列头部的内存块。

下面是一段FIFO算法下的示例序列:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Beladay异常当为进程分配的物理块数增大时,缺页次数不减反增的异常现象

只有 FIFO 算法会产生 Belady异常。另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,算法性能差

2.5.3 最近最少使用(LRU)

最近最少使用算法(LRU):淘汰最近一次访问距当前时间最长的。

实现方式:用双向链表实现一个链式栈,页面每次访问都从栈底拿出放到栈顶。

示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

OJ练习

146. LRU Cache

附个py代码

class Node:
    __slots__ = 'prev', 'next', 'key', 'value'
    def __init__(self, key=0, value=0):
        self.key = key
        self.value = value

class LRUCache:

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.dummy = Node()
        self.dummy.prev = self.dummy.next = self.dummy
        self.mp = dict()

    # 按key获取node,同时放到链头
    def get_node(self, key: int) -> Optional[Node]:
        if key not in self.mp:
            return None
        res = self.mp[key]
        self.remove(res)
        self.push_front(res)
        return res

    # 获取值
    def get(self, key: int) -> int:
        node = self.get_node(key)
        return node.value if node else -1

    # 插入 or 更新
    def put(self, key: int, value: int) -> None:
        node = self.get_node(key)
        if node:
            node.value = value
            return
        self.mp[key] = node = Node(key, value)
        self.push_front(node)
        if len(self.mp) > self.capacity:
            # LRU替换
            rm = self.dummy.prev
            self.remove(rm) # 替换最后一个
            del self.mp[rm.key] # 从哈希表中删除key

    # 删除结点,断开连接
    def remove(self, rm: Node) -> None:
        rm.prev.next = rm.next
        rm.next.prev = rm.prev

    # 链表头插
    def push_front(self, x: Node) -> None:
        x.prev = self.dummy
        x.next = self.dummy.next
        x.prev.next = x
        x.next.prev = x

# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
2.5.4 最近不用的先淘汰

最近不用的先淘汰(not used recently):淘汰最近一段时间未用到的。

实现:每页增加一个访问标志,访问置1,定时清0,淘汰时取标志为0的。

事实上是LRU的下位替代。

2.5.5 最不经常使用的先淘汰(LFU)

最不经常使用的先淘汰(LFU):淘汰使用次数最少的。

依据:活跃访间页面应有较大的访问次数

坏的情形:

  • 前期使用多,但以后不用,难换出
  • 刚调入的页面,引用少,被换出可能大

实现:记数器,调入清0,访问增1,淘汰选取最小者

OJ练习

460. LFU Cache

同样贴个py代码

class Node:
    __slot__ = 'prev', 'next', 'key', 'value', 'freq'

    def __init__(self, key=0, val=0):
        self.key = key
        self.value = val
        self.freq = 1


class LFUCache:

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.mp = dict()
        # 创建哨兵接口
        def new_list() -> Node:
            dummy = Node()
            dummy.prev = dummy.next = dummy
            return dummy

        self.freq_to_dummy = defaultdict(new_list)

    # 按key拿结点,注意调整freq
    def get_node(self, key: int) -> Optional[Node]:
        if key not in self.mp:
            return None
        res = self.mp[key]
        self.remove(res)
        dummy = self.freq_to_dummy[res.freq]
        if dummy.prev == dummy:
            del self.freq_to_dummy[res.freq]
            if self.min_freq == res.freq:
                self.min_freq += 1
        res.freq += 1
        self.push_front(self.freq_to_dummy[res.freq], res)
        return res

    def get(self, key: int) -> int:
        node = self.get_node(key)
        return node.value if node else -1

    # 插入/更新结点,替换freq最低的
    def put(self, key: int, value: int) -> None:
        node = self.get_node(key)
        if node:
            node.value = value
            return
        if len(self.mp) == self.capacity:
            dummy = self.freq_to_dummy[self.min_freq]
            rm = dummy.prev
            del self.mp[rm.key]
            self.remove(rm)
            if dummy.prev == dummy:
                del self.freq_to_dummy[self.min_freq]
        self.mp[key] = node = Node(key, value)
        self.push_front(self.freq_to_dummy[1], node)
        self.min_freq = 1

    def remove(self, x: Node) -> None:
        x.prev.next = x.next
        x.next.prev = x.prev

    def push_front(self, dummy: Node, x: Node) -> None:
        x.prev = dummy
        x.next = dummy.next
        x.prev.next = x.next.prev = x

# Your LFUCache object will be instantiated and called as such:
# obj = LFUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
2.5.6 最频繁使用算法

最频繁使用算法(MFU):淘汰使用次数最多的。

依据:使用多的可能已经用完了。

坏的情形:程序有些成分是在整个程序运行中都使用的

2.5.7 二次机会

**二次机会(second chance)**算法:淘汰装入最久且最近未被访问的页面。

算法流程:

  • 双向链表,结点额外增加标记位,1代表访问过,0代表未访问
  • 从表头开始往后遍历
  • 遇到标记位为1的将其置为0,然后移到链尾
  • 遇到标记位为0的,将其替换为新插入的结点,然后移到链尾
  • 算法结束

示例如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.5.8 时钟算法

时钟(clock)算法流程:

  • 将页面组织成环形,有一个指针指向当前位置。
  • 每次需要淘汰页面时,从指针所指的页面开始检查。
  • 如果当前页面的访问位为0,即从上次检测到目前,该页没有访问过,则将该页替换。
  • 如果当前页面的访问位为1,则将其清0,并顺时针移动指针到下一个位置
  • 重复上述步骤直至找到一个访问位为0的页面。

可以看出,时钟算法与二次机会算法的淘汰效果是基本相同的,差别在于二者所采用的数据结构不同,二次机会使用的是链表,需要额外存储空间,且摘链入链速度很慢。而时钟算法可直接利用页表中的引用位外加一个指针,速度快且节省空间。

2.5.9 改进的时钟算法

**时钟算法的可改进之处:**简单的时钟置换算法仅考虑到一个页面最近是否被访问过。事实上,如果被淘汰的页面没有被修改过
就不需要执行I0操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存

因此,除了考虑一个页面最近有没有被访问过之外,操作系统还应考虑页面有没有被修改过。

在其他条件都相同时,应优先淘汰没有修改过的页面,避免I/O操作。这就是改进型的时钟置换算法的思想。

修改位=0,表示页面没有被修改过;修改位=1,表示页面被修改过。

考虑访问位r,标记位m

  • r=0,m=0;最佳淘汰页面

  • r=0,m=1;淘汰前回写

  • r=1,m=0;不淘汰

  • r=1,m=1;不淘汰

算法流程:

  • 将所有可能被置换的页面排成一个循环队列
  • 第一轮:从当前位置开始扫描到**第一个(0,0)**的页面用于替换。本轮扫描不修改任何标志位
  • 第二轮:若第一轮扫描失败,则重新扫描,查找**第一个(0,1)**的页面用于替换。本轮将所有扫描过的页面访问位设为0
  • 第三轮:若第二轮扫描失败,则重新扫描,查找**第一个(0,0)**的用于替换。本轮扫描不修改任何标志位
  • 第四轮:若第三轮扫描失败,则重新扫描,查找第一个(0,1)的用于替换。
  • 由于第二轮已将所有帧的访问位设为0,因此经过第三轮、第四轮扫描一定会有一个页面被选中,因此改进型CLOCK置换算法选择一个淘汰页面最多会进行四轮扫描

示例:

假定某进程在内存中分得8个页框,分别保存该进程的6、3、12、8、7、9、0、1页面,现在要访问页面 15,该页不在内存中,发生缺页中断。由于没找到0,0,所以我们找了一圈后又从页8开始找10,找到页9替换,同时注意:7、8的r被置1了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.6 颠簸的概念

颠簸(又称抖动):页面在内外存之间频繁换入换出。

主要原因:

  • 分配给进程的物理页框不够
  • 淘汰算法不合理

处理方法:

  • 增加分配给进程的物理页框数
  • 改进淘汰算法

思考题:在某些虚拟页式存储管理系统中,内存中总保持一个空闲的物理页架,这样做有什么好处?

1.在内存没有空闲页架的情况下,需要按照置换算法淘汰一个内存页架,然后读入所缺页面,缺页进程一般需要等待两次I/O传输(写外存,读外存)。

2.若内存总保持一个空闲页架,当发生页故障时,所缺页面可以被立即调入内存的这个空闲页架,缺页进程只需等待一次I/O传输时问。读入后立即淘汰个内存页面,此时可能也需执行一次I/O传输,但对缺页进程来说不需等待,因而提高了响应速度。

2.7 工作集模型(working set model)

**驻留集:**指请求分页存储管理中给进程分配的内存块的集合

**工作集(working set)**是进程在一段时间之内活跃地访问页面的集合。

WS(t,Δ)代表[t - Δ, t]内的工作集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显然工作集大小与窗口尺寸密切相关

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

窗口尺寸确定:

Madnick Donovan 建议:Δ = 1万次访内

  • 过小:活动页面不能全部装入,页故障率高
  • 过大:内存浪费。

实现页表中增加访间位

Δ开始时,全部清 0

访问:置 1,
Δ结束时(新Δ开始时)访问标志为1的,为该期间工作集,
τ n + 1 = α w n + ( 1 − α ) τ n \tau_{n+1} = \alpha w_n+ (1-\alpha)\tau_n τn+1=αwn+(1α)τn

其中:

  • w n w_n wn为第n个△周期实际工作集大小;
  • τ n \tau_n τn 为第n个△周期工作集估算值;
  • α通常取值为 0.5。

2.8 页故障率反馈模型

PPFB(Page Fault Feed Back)

  • 页故障率 = 访问内存缺页次数 / 访间内存总次数
  • **思想:**利用页故障率反馈信息,实现动态调整页框的分配。

页故障率高(达到某上界阈值):内存页面少,增加。

页故障率低(达到某下界阈值):内存页面多,减少。

三、虚拟段式存储系统

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.1 基本原理

  • 虚拟段式存储管理的思想与虚拟页式存储管理相似,只是将页变为段
  • 进程运行前将主程序段装入内存,其他段装入外存储器。
  • 运行时所需的段如果不在内存,将其动态调入。
  • 如果内存没有足够的空间,可以采取两种方法:
    • 紧凑,即将内存中的所有空闲区合并
    • 淘汰,即将内存中的某段移至外存储器,

段的淘汰可以采用与页式存储管理相似的算法。虚拟段式存储管理方式的工作原理如下:

虚拟段式相比物理段式存储,段表也要进行改进:

增加:外存首址,外存首址(之前只有内存段首址寄存器),修改标志,内外标识

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

快表改进:

快表显然不保存外存的内容,所以不需要外存首址,内外标识

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.2 段的动态连接

3.2.1 为什么要有动态连接

静态连接:在程序运行之前将各段连接在一起,该连接是由连接装配程序完成的。

  • 优点:简单
  • 缺点:连接时间长,所产生的目标代码长,所连接的段在程序运行过程中不一定都能用得到。

为了克服其缺点,提出了动态连接

3.2.2 动态连接的实现(Multics 为例)

静态连接每个程序的段的数目确定,连接装配程序为每一段分配一个段号,段名到段号的转换可以由连接装配程序完成。

动态连接中,一个程序有多少段是不确定的,所以段名到段号的转换由操作系统完成。

动态连接实现:

段名-段号对照表:每进程一个,记录当前已连接段的表目。

符号表:每段一个,每一个符号名转换为对应的段内地址。每个段在编译(汇编)时都需要生成一个符号表。

动态连接的步骤:

编译(汇编)时:

遇到访问外段指令,采用间接寻址,指向一个间接字:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

L = 1,表示需要动态连接

执行时:

遇到间接指令,且 L = 1,发生链接中断,处理程序:

(1)由D取出符号地址;
(2)由段名查段名 - 段号对照表,是否分配段号。

  1. 该段已经被分配段号,这说明该段以前曾经连接过,将该段号由段名-段号对照表中取出,然后由段号查找段表找到该段,继而由单元名查找该段的符号表,从中取出段内地址,然后将段号和段内地址赋给 D,0赋给L。
  2. 该段未分配段号,这说明该段以前未连接过。将该段由文件系统调入内存中,分配一个段号,填写段名-段号对照表,然后转步骤2。
3.2.3 动态连接的问题

动态连接与共享的矛盾

动态连接:需要修改连接字

段的共享:又要求纯代码(pure code),运行过程中不能改变自身

解决方法

共享代码分为“纯段”和“杂段”

  • “纯段共享”
  • “杂段私用”

四、虚拟段页式管理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

思考之前为什么要对内存进行段页式存储管理:

  • 结合页式存储和段式存储的优点,克服二者缺点
  • 前者实现离散分配,没有碎片,但是对操作者透明;后者可以实现段长动态变化,且操作者可以编程控制,但是会有碎片

不过虚拟段页式实现复杂,需要硬件提供更多支持。

4.1 基本原理

1、所需表目:

**段表:**每进程一个

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**页表:**每段一个

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**总页表:**即位图,内存和外存储器各有一个,其形式与非虚拟存储管理一致。

**共享段表:**整个系统有一个共享段表,记录所有共享段。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**段名-段号对照表:**每个进程有一个段名-段号对照表,其形式与非虚拟存储管理方式完全相同。

2、表间联系:

非共享段:段表指向页表

共享段:段表指向共享段表

共享段表:指向页表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3、所需寄存器

  1. 段表长度寄存器:整个系统有一个,保存正运行进程段表长度
  2. 段表首址寄存器:整个系统有一个,保存正运行进程段表首址
  3. 快表:每个进程有一个

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4、地址映射

逻辑地址(段号,逻辑页号,页内地址)= (s,p,d);

物理地址(页框号,页内地址)=(f,d)

5、中断处理

  1. 连接中断

    由段名查找本进程的段名-段号对照表及共享段表,经判断可以分为以下3种情形。

    1. 所有进程均未连接过(共享段表、段名-段号对照表均无)。查文件目录找到该段;为该段建立页表,由文件全部读入交换空间,部分读入内存,填写页表;为该段分配段号,填写段名-段号对照表;如果该段可以共享,填写共享段表,共享计数值置1;填写段表;根据段号及段内地址形成无障碍指示位的一般间接地址。
    2. 其它进程连接过,本进程未连接过(共享段表有,段名-段号表无)。为该段分配段号;填写段名-段号对照表,填写段表(指向共享段表),共享段表中的共享计数值加1;根据段号及段内地址形成无障碍指示位的一般间接地址。
    3. 本进程已经连接过(共享段表有或无,段名-段号对照表有)。根据段号及段内地址形成无障碍指示位的一般间接地址。
  2. 缺页中断

    将对应页面调入内存,同时更新页表及页面分配表。

  3. 越界中断

    越界中断可分为段号越界段内页号越界这两种情形。
    ① 段号越界。即访问并不存在的段,地址错误,程序将被中止。
    ② 段内页号越界。即访问段内并不存在的页,根据段扩充标志判断该段是否可以扩充,如果可以扩充,动态增长该段,即为该段申请新页,并修改页表和段表;如果不可扩充,地址错误,程序将被中止。

  4. 越权中断

    违反段的访问权限,程序将被中止。

4.2 各种虚拟存储管理系统特性比较

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

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

相关文章

Oracle详情数据库索引事务视图触发器分区发生死锁数据字典【Oracle】

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

乐鑫ESP32-WROOM-32E模组设备低功耗控制方案,启明云端乐鑫代理商

在数字化浪潮的推动下,物联网(IoT)正迅速成为我们日常生活的一部分。而在这个领域中,ESP32-WROOM-32E模组以其卓越的性能和多功能性,成为了开发者和制造商的选择。 ESP32-WROOM-32E模组集成了ESP32-D0WD-V3芯片&#…

宝塔面板部署前端项目

部署前端项目 1 打包自己的项目2 登录宝塔面板3 添加站点4 设置域名5 进入当前站点对应的文件目录中6 上传打包后的文件7 访问网站 1 打包自己的项目 2 登录宝塔面板 点击左侧“网站”菜单进入对应页面 点击“添加站点” 3 添加站点 填写域名,如果没有域名的&am…

重生奇迹MU 谁才是真正的全能职业

重生奇迹MU中,游戏的奥妙就在于职业的选择。不同职业间各有千秋,可远可近,全都是玩家们心中的全能职业。本文就将为你分析重生奇迹MU中的各个职业,为你解答谁才是真正的全能职业。 每次新开一个服务器时,玩家们总会纠结…

为什么不推荐在自动化测试中使用单例模式

简述 尽管在国内大量的代码中使用单例这种简单的方式,但在自动化测试过程中会导致很多问题。因此,在自动化测试中,不推荐使用单例模式。 什么是单例? 《设计模式:可复用面向对象软件的基础》一书(通常被称为…

2024地理信息相关专业大学排名

在开始之前,不得不提一下今年福耀科技大学不能招生的遗憾,不知道明年是否能一切准备就绪开始招生呢? 如果这所大学能招生了,不知道它有没有地理信息相关专业呢? 言归正转,我们现在就基于公开资料&#xf…

vue:响应式原理解析,深入理解vue的响应式系统

一、文章秒读 vue的响应式系统核心有两个,简单描述就是: 1.在数据变化时重新render依赖相关函数(组件)。 2.在vue2和vue3中分别使用Object.defineProperty和Proxy进行对象属性的读写。 数据变化时: 二、什么是响应…

解决宝塔linux面板 - 404 Not Found(Nginx)方法

宝塔Linux面板后台登录提示404 Not Found Nginx如何解决?码笔记:这是因为BT面板丢失了安全登录入口,如下图: 宝塔404 Not Found nginx 解决方法: 1、先SSH远程服务器 2、然后执行命令 bt 14 重新获取宝塔面板URL地址安…

Linux安装frp实现内网穿透

Linux运维工具-ywtool 目录 一. 简介二.代理类型三.frp支持的Linux的架构四.安装1.准备工作2.配置frp服务器端(a)下载安装包(b)解压安装包(c)修改配置文件(d)启动服务端 3.配置frp客户端(a)下载安装包并修改配置文件(b)启动客户端 4.测试连接 五.其他1.多端口穿透(a)服务端(b)客…

wireshark工具获取设备IP地址

背景: 一个网口抓包工具,主要是升级XX设备时候不知道网口的ip地址。每次需要一个一个试,比较麻烦。 使用步骤: 1、连接好XX设备与笔记本,在网络连接里面找到以太网,没有出现红色X号,表示网线连…

【道合顺展会预告】2024国际传感器仪器仪表物联网长沙展览会!

传感器技术作为万物互联的基石,正以前所未有的速度驱动着全球各行各业的转型升级。在此背景下,2024国际传感器&仪器仪表&物联网展览会将于6月28日至30日在长沙盛大启幕,道合顺传感将携公司最新技术及科研成果参加展览会,并…

数据库自动备份到gitee上,实现数据自动化备份

本人有个不太好的习惯,每次项目的数据库都是在线上创建,Navicat 连接线上数据库进行处理,最近有一个项目需要二次升级,发现老项目部署的服务器到期了,完蛋,数据库咩了!!!…

开源模型应用落地-FastAPI-助力模型交互-WebSocket篇(一)

一、前言 使用 FastAPI 可以帮助我们更简单高效地部署 AI 交互业务。FastAPI 提供了快速构建 API 的能力,开发者可以轻松地定义模型需要的输入和输出格式,并编写好相应的业务逻辑。 FastAPI 的异步高性能架构,可以有效支持大量并发的预测请求,为用户提供流畅的交互体验。此外,F…

在Qt中,直接include <moc_xxxxx.cpp> 为什么不会出现符号冲突的错误?

在逛Qt官方社区的时候看到这样一个帖子: https://forum.qt.io/topic/117973/how-does-include-moc_-cpp-work 大概的意思是moc_xxx.cpp如果已经被编译器编译,那么在另一个cpp文件中include同一个moc_xxx.cpp应该出现符号冲突才对,但是Qt却能正…

关于如何更好管理好数据库的一点思考

本文尝试从数据库设计理论、ER图简介、性能优化、避免过度设计及权限管理方面进行思考阐述。 一、数据库范式 以下通过详细的示例说明数据库范式的概念,将逐步规范化一个例子,逐级说明每个范式的要求和变换过程。 示例:学生课程登记系统 初始…

提效优化:企业IT人员视角下的SD-WAN经验分享

我是公司IT支持人员,主要职责是确保公司的网络系统运行顺畅,让同事们能够顺利地完成他们的工作。随着公司业务的扩展和远程办公的普及,我工作中面临的挑战也日益严峻。 永无止境的问题流是我们IT人员日常工作中最为常见的现象。从“网络怎么这…

Spring Boot启动报错Lombok supports: sun/apple javac 1.6, ECJ

版本 idea 2023.3.4 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.32</version></dependency> 解决方式 File->Settings->Build, Execution, Deployment->Com…

录音转文字app哪个最好?5款实用的录音转文字软件下载

随着录音记录的普及&#xff0c;录音转文字功能已成为日常工作和学习中不可或缺的助手。 无论是会议记录、课堂笔记还是采访录音&#xff0c;这项技术都能快速、准确地将语音内容转换为文字。面对市场上众多的转文字软件&#xff0c;你知道录音转文字app哪个最好吗&#xff1f…

H5实现第三方分享功能,(WhatsApp,Facebook,Messenger,Instagram,Telegram,Zalo,Twitter/X)

1. H5实现第三方分享功能 1. WhatsApp 分享 https://api.whatsapp.com/send/?phone&app_absent0&text${codeUrl}2. Facebook 分享 https://www.facebook.com/sharer/sharer.php?u${codeUrl}3. Messenger 分享 https://www.messenger.com/?${codeUrl}4. Instagra…

Redis集群-计算key的插槽值等命令

文章目录 1、集群方式登录主机63792、计算key应该保存在那个插槽3、计算某个插槽中保存的key的数量4、返回指定槽中的键 1、集群方式登录主机6379 [rootlocalhost redis]# /usr/local/redis/bin/redis-cli -c -h 192.168.74.148 -p 6379 192.168.74.148:6379> keys * 1) &q…