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

news2024/10/6 5:54:21

文章目录

    • @[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 各种虚拟存储管理系统特性比较

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

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

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

相关文章

Transformer的诞生和崛起

智能问答与文本生成:Transformer模型的超能力 ©作者|wy 来源|神州问学 一、引言 NLP(自然语言处理)作为人工智能领域的一个重要分支,致力于使计算机能够理解和处理人类语言。随着互联网的发展和信息时代的到来,…

docker 容器设置中文环境

1.容器中安装和设置 1.1.进入容器查看已有语言包 locale -a 默认情况下: 1.2 安装中文语言环境 如果没有zh_CN.utf8就安装。 方式1: #直接安装中文语言包 apt-get install -y language-pack-zh-hans 方式2: #安装中文语言环境 apt-g…

系统初始化进程与文件、systemd概述、单元类型、切换运行级别、查看系统默认默认运行、永久切换、常见的系统服务(centos)

init进程 init进程是Linux系统(“/sbin/init”)中的第一个进程,它是所有其他进程的祖先进程。init进程的进程号(PID)始终为1。它负责启动和停止系统中的所有其他进程,以及处理系统的各种系统级任务。 ini…

大模型系列之被我忽视的Assistants API

前言 在这篇文章中,我们提到在GPT4.0 turbo发布时,GPTs和Assistants API的出现使得众多创业者一夜无眠。当时看完之后就被我丢到一边,并没有太多关注,随着我们对RAG和Agent的不断深入了解,蓦然回首,越发感…

HarmonyOS Next开发学习手册——通过startAbility拉起文件处理类应用

使用场景 开发者可以通过调用startAbility接口,由系统从已安装的应用中寻找符合要求的应用来实现打开特定文件的意图,例如:浏览器下应用下载PDF文件,可以调用此接口选择文件处理应用打开此PDF文件。开发者需要在请求中设置待打开…

Redis-实战篇-什么是缓存-添加redis缓存

文章目录 1、什么是缓存2、添加商户缓存3、前端接口4、ShopController.java5、ShopServiceImpl.java6、RedisConstants.java7、查看Redis Desktop Manager 1、什么是缓存 缓存就是数据交换的缓冲区(称为Cache),是存贮数据的临时地方&#xff…

Linux 异步 I/O 框架 io_uring:基本原理、程序示例与性能压测

Linux 异步 I/O 框架 io_uring 前言Linux I/O 系统调用演进io_uring与 Linux AIO 的不同原理及核心数据结构:SQ/CQ/SQE/CQE带来的好处三种工作模式io_uring 系统调用 API 前言 io_uring 是 2019 年 Linux 5.1 内核首次引入的高性能 异步 I/O 框架,能显著…

【干货】Jupyter Lab操作文档

Jupyter Lab操作文档1. 使用须知2. 定制化Jupyter设置主题显示代码行数设置语言更多设置 3. 认识Jupyter界面4. 初用Jupyter运行调试格式化查看源码 5. 使用Jupyter Terminal6. 使用Jupyter Markdown7. 上传下载文件(云服务器中的Jupyter Lab)上传文件到…

SAP的RFID

射频识别 (RFID) 避免了条码扫描的局限性,条码扫描需要对每个条码进行视线访问,并且一次只能用于扫描一个项目。 一次扫描一个标签可能会令人厌烦和压力大,这会增加人为错误的机会。相反,RFID 标签不需要直…

入局AI手机 苹果公布Apple Intelligence

日前,苹果WWDC 2024如期召开。在这持续1个小时44分钟的开发者大会上,苹果在前一个小时里更新了iOS、iPadOS、MacOS等操作系统,而且还首次更新了visionOS。余下的时间全部留给了苹果的“AI大礼包”——Apple Intelligence(苹果智能…

全网最强SpringMVC教程 | 万字长文爆肝SpringMVC(一)

SpringMVC_day01 今日内容 理解SpringMVC相关概念完成SpringMVC的入门案例学会使用PostMan工具发送请求和数据掌握SpringMVC如何接收请求、数据和响应结果掌握RESTful风格及其使用完成基于RESTful的案例编写 SpringMVC是隶属于Spring框架的一部分,主要是用来进行We…

JavaWeb系列六: 动态WEB开发核心(Servlet) 上

韩老师学生 官网文档为什么会出现Servlet什么是ServletServlet在JavaWeb项目位置Servlet基本使用Servlet开发方式说明快速入门- 手动开发 servlet浏览器请求Servlet UML分析Servlet生命周期GET和POST请求分发处理通过继承HttpServlet开发ServletIDEA配置ServletServlet注意事项…

Ollama模型部署工具在Linux平台的部署

1.新建普通用户dmx(可选) [rootnode3 ~]$ useradd dmx2.切换普通用户dmx环境(可选) [dmxnode3 ~]$ su - dmx3.下载ollama-linux-amd64服务 下载ollama-linux-amd64到 ~/server目录,并将ollama-linux-amd64服务重命名为ollamaEED curl -L …

07 - matlab m_map地学绘图工具基础函数 - 绘制等高线

07 - matlab m_map地学绘图工具基础函数 - 绘制等高线 0. 引言1. 关于绘制m_contour2. 关于绘制m_contourf3. 关于绘制m_elev4. 结语 0. 引言 本篇介绍下m_map中添加绘制等高线的一系列函数及其用法,主要函数包括m_elev、m_contour、m_contourf还有一些函数也和绘制…

线性和二次判别分析

线性判别分析 线性判别分析(Linear Discriminant Analysis,LDA)亦称 Fisher 判别分析。其基本思想是:将训练样本投影到低维超平面上,使得同类的样例尽可能近,不同类的样例尽可能远。在对新样本进行分类时&…

Spring+Vue项目部署

目录 一、需要的资源 二、步骤 1.首先要拥有一个服务器 2.项目准备 vue: 打包: 3.服务器装环境 文件上传 设置application.yml覆盖 添加启动和停止脚本 ​编辑 安装jdk1.8 安装nginx 安装mysql 报错:「ERR」1273-Unknown collation: utf8m…

ROS2中的CMakeLists(一)——基础知识

在使用ROS2框架开发机器人应用时,对各个功能包Cmakelist.txt文件的更改尤为重要。本系列旨在总头开始介绍Cmakelist.txt各条语句的意义和内涵。 Cmake已经是高度集成的构建工具,其作用是在不同开发环境下生成makefile文件,以此来执行make指令…

聊聊 System.Linq.Dynamic,以及分享一个使用 System.Linq.Dynamic 扩展 LINQ 查询的详细例子

前言:System.Linq.Dynamic 是什么? System.Linq.Dynamic 扩展了 .NET 中的 LINQ 查询功能,通过它,我们可以在运行时动态构造 LINQ 查询表达式,就像是写原生 SQL 语句一样,更加灵活直观。 利用 System.Lin…

FPGA学习笔记(5)——硬件调试与使用内置的集成逻辑分析仪(ILA)IP核

如果要对信号进行分析,可以使用外置的逻辑分析仪,但成本较高,对初学者来说没有必要,可以使用Xilinx Vivado内自带的逻辑分析仪IP核对信号进行分析,不过需要占用一定的芯片资源。 本节采用上一节配置的LED灯闪烁代码&a…