首页 > 系统相关 >校招基础知识详解——计算机操作系统(内存管理)

校招基础知识详解——计算机操作系统(内存管理)

时间:2024-10-22 09:17:15浏览次数:3  
标签:lst 基础知识 算法 详解 内存 key 校招 虚拟内存 页面

文章目录

虚拟内存

虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。

为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。

从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。

在这里插入图片描述

虚拟内存可以让每个进程以为自己独占整个内存

虚拟内存可以在逻辑上扩充物理内存,比如GTA5这个游戏,本身有游戏大小60G,而内存只有8G,没有虚拟内存话,那么就无法将60G的游戏从硬盘放到8G的内存中,即无法运行GTA5

而有了虚拟内存,就可以运行GTA5了,将需要运行的部分程序代码放入内存,需要用到什么就判断内存有没有,没有就载入,不需要用的就替换出去放回硬盘。

分页系统地址映射

内存管理单元(MMU)管理着地址空间和物理内存的转换,其中的页表(Page table)存储着页(程序地址空间)和页框(物理内存空间)的映射表。

一个虚拟地址分成两个部分,一部分存储页面号,一部分存储偏移量。

下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址(0010 000000000100),前 4 位是存储页面号 2,读取表项内容为(110 1),页表项最后一位表示是否存在于内存中,1 表示存在。后 12 位存储偏移量。这个页对应的页框的地址为 (110 000000000100)。

在这里插入图片描述

页面置换算法

在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。

页面置换算法和缓存淘汰策略类似,可以将内存看成磁盘的缓存。在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。

页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。

最佳页面置换算法(OPT, Optimal replacement algorithm)

所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。

是一种理论上的算法,因为无法知道一个页面多长时间不再被访问。

举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:

7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1

开始运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。

在这里插入图片描述

在这里插入图片描述

先进先出置换算法(FIFO, First In First Out)

选择换出的页面是最先进入的页面。

该算法会将那些经常被访问的页面换出,导致缺页率升高。

在这里插入图片描述

在这里插入图片描述

最近最久未使用的置换算法(LRU, Least Recently Used)

虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。

为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。

因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

对应 Leetcode—146. LRU 缓存【中等】

struct Node {
    int key;
    int val;
};

class LRUCache {
public:
    LRUCache(int capacity) : m_capacity(capacity) {
        
    }
    
    int get(int key) {
        const auto & it = mp.find(key);
        // key 不存在
        if(it == mp.cend()) {
            return -1;
        }
        // key 存在
        const auto& lsNode = it->second;
        lst.splice(lst.begin(), lst, lsNode);
        return lsNode->val;
    }
    
    void put(int key, int value) {
        // key 存在, 变更val
        if(const auto it = mp.find(key); it != mp.cend()) {
            const auto& lsNode = it->second;
            lst.splice(lst.begin(), lst, lsNode);
            lsNode->val = value;
            return;
        }

        // key 不存在
            // 容量已满
        if(m_capacity == mp.size()) {
            auto & item = lst.back();
            mp.erase(item.key);
            lst.pop_back();
        }
            // 容量有余
        lst.emplace_front(key, value);
        mp[key] = lst.begin();
    }
private:
    const int m_capacity;
    list<Node> lst;
    unordered_map<int, list<Node>::iterator> mp;
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */

最不常用算法

在这里插入图片描述

最近未使用(NRU, Not Recently Used)

在这里插入图片描述

第二次机会算法

FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改:

当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。

在这里插入图片描述

时钟页面置换算法(Clock)

第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

分段

虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页,每一页再与内存进行映射。

下图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。

在这里插入图片描述

分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。

在这里插入图片描述

段页式

程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

分页与分段的比较

在这里插入图片描述

Linux 内存管理

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这 7 个内存段中,堆和文件映射段的内存是动态分配的。比如说,使用 C 标准库的 malloc() 或者 mmap() ,就可以分别在堆和文件映射段动态分配内存。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
之后我会持续更新,如果喜欢我的文章,请记得一键三连哦,点赞关注收藏,你的每一个赞每一份关注每一次收藏都将是我前进路上的无限动力 !!!↖(▔▽▔)↗感谢支持!

标签:lst,基础知识,算法,详解,内存,key,校招,虚拟内存,页面
From: https://blog.csdn.net/qq_44631615/article/details/143033666

相关文章

  • LLM学习-基础知识
    NLPNLP代表自然语言处理,是关于计算机和人类语言之间交互的领域。NLP涵盖了一系列任务,包括文本处理、语音识别、语言翻译、信息检索等。NLP技术的发展使得计算机能够理解、解释和生成人类语言,促进了许多领域的发展,包括智能助手、文本分析、情感分析等。LLMLLM指的是大型语言模型......
  • visual studio之安装详解
    目录1VisualStudio1.1下载&安装1.1.1下载1.1.2安装1.1.3选择组件1.1.4安装位置1.2启动操作1.3更改组件1.3.1添加新组件1.3.1.1打开的项目1.3.1.2通过installer修改1.3.2修改共享组件、工具和SDK安装位置1.4C#中操作1.4.1控制台程序输出HelloWorld1.4.2Windows......
  • LinkedList详解
    1概述LinkedList和ArrayList是Java集合框架中的两个重要类,它们分别基于链表和动态数组实现。LinkedList选择链表作为其底层数据结构的原因在于链表在某些操作上具有显著的优势。1.1链表的优势动态大小:链表不需要预先分配固定大小的内存,可以根据需要动态扩展或缩......
  • hadoop_hdfs详解
    HDFS秒懂HDFS定义HDFS优缺点优点缺点HDFS组成架构NameNodeDataNodeSecondaryNameNodeClientNameNode工作机制元数据的存储启动流程工作流程SecondaryNameNode工作机制checkpoint工作流程DataNode工作机制工作流程数据完整性文件块大小块太小的缺点块太大的缺点文......
  • 六、栈————相关概念详解
    栈————相关概念详解前言一、栈(stack)1.1栈是什么?1.2栈的类比二、栈的常用操作2.1初始化栈2.2元素入栈2.3访问栈顶元素2.4元素出栈2.5获取栈的长度2.6判断是否为空三、栈的实现3.1基于数组实现栈3.1.1代码演示3.1.2上述代码不足3.2基于链表实现栈3.2......
  • 类加载过程详解
    类的生命周期类从被加载到虚拟机内存中开始到卸载出内存为止,它的整个生命周期可以简单概括为7个阶段:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)。其中,验证、准备和解析这三个阶段可以统称为连接(Link......
  • 【机器学习】朴素贝叶斯详解
    朴素贝叶斯朴素贝叶斯介绍复习常见概率的计算知道贝叶斯公式了解朴素贝叶斯是什么了解拉普拉斯平滑系数的作用【知道】常见的概率公式条件概率:表示事件A在另外一个事件B已经发生条件下的发生概率,P(A|B)在女神喜欢的条件下,职业是程序员的概率?女神喜欢条件下......
  • Swagge详解,SpringBoot项目集成Swagger
    介绍        相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接......
  • 反射-Class类详解
    概述        在Java中,除了int等基本类型外,Java的其他类型全部都是class(包括interface)。例如:StringObjectRunnableException...        Java反射机制是Java语言的一个重要特性。在学习Java反射机制前,大家应该先了解两个概念:编译期和运行期。     ......
  • Java消息队列入门详解
    什么是消息队列?消息队列的产生主要是为了解决系统间的异步解耦与确保最终一致性。在实际应用场景中,往往存在一些主流程操作和辅助流程操作,其中主流程需要快速响应用户请求,而辅助流程可能涉及复杂的处理逻辑或者依赖于外部服务。通过将这些辅助流程的消息放入消息队列,使得它们可......