详细分析置换算法

news2024/11/24 8:05:45

对于操作系统而言,虚拟空间是非常大的,我们往往无法直接将如此大的空间装入内存,而即使我们采用多级页表与段页式存储即使,也仅仅只是节省了页表的大小,如此将如何多的物理页装进内存仍然是一个问题,为此科学家们提出了一种动态的思想,当剩余空间不够装入新页面时,操作系统就选择适当的页将其刷新回磁盘(如果确实是脏页的话,如果不是脏页则仅仅只是覆盖),以此空出空间装入新页,而这则需要运用到页面置换算法。

还有一个问题是:是否需要对每一个进程固定一个空间大小,换句话说,是采用局部分配策略还是全局分配策略。

采用局部分配的好处在于每一个进程空间都是互不影响的,即使一个进程频繁的发生页面置换也不会影响到其他进程,并且易于管理;但缺点是,如何分配一个进程的空间大小是难以确定的,有的进程可能频繁发生页面置换,而有的进程可能只会使用一点点空间,这是预先无法确定的,如果给一个进程分配的空间小了,那么该进程可能会发生内存“颠簸”(频繁的发生页面置换)。

若采用全局分配,一个进程理论上可以使用整个内存空间,内存大意味着发生置换的频率就小了,在绝大多数情况下,全局分配优于局部策略。但缺点也是很明显的,如果进程较多,一个进程频繁进行页面置换可能会置换其他进程的页,这可能会导致其他进程也造成缺页异常,需要引入新页,从而造成死循环。这是操作系统不愿意看到的事情,而且操作系统难以控制这种局面。

目前现代操作系统非常智能,现代操作系统大多采用局部分配的方法,这更易于操作系统控制。当操作系统开始分配页面时,会根据进程数量、进程资源大小等参数相对公平的分配固定的空间,例如总内存大小为 10kb,当已有一个资源为 5kb 的进程A正在运行,由于只有一个进程,进程A的空间大小为整个内存大小 10kb,现在操作系统打算为资源大小为 15kb 的进程B分配空间,操作系统根据进程大小与进程数量进行评估,由于进程B大小 : 进程A大小 = 3 : 1,因此操作系统为B分配 3/4 的内存空间大小 7.5kb,同时调整A的大小为 2.5kb(淘汰页面)。

在运行时,操作系统仍然会进行动态调整,如果一个进程A频繁的发生颠簸,而进程B几乎不发生颠簸,操作系统会适当增加进程A空间的大小,而减少进程B空间的大小。如果所有的进程都发生颠簸,这是最坏的情况,此时操作系统会选择一些进程将它们暂时的调换到磁盘中以空处一些空间,直到有新的空间时再将他们换回来。

何时会发生页面置换?程序执行期间,若程序所要访问的页面未在内存时,发生缺页异常(页表项中存在位为0),需要引入该页。中断处理程序首先保留CPU环境,转入缺页中断处理程序。查找页表,得到该页在外存的物理块后,

如果内存未满,则将缺页调入内存并修改页表。

如果内存已满,则按照某种置换算法从内存中选出一页换出;如果该页未被修改过,可不必将该页写回磁盘;但如果此页已被修改,则必须将它写回磁盘,然后再把所缺的页调入内存,并修改页表中的相应表项,置其存在位为“1”,并将此页表项写入快表中。如果此时进程的内存空间不够,则需要淘汰一些页面,这就是页面置换。

在了解这些之后,让我们来具体探讨一些页面淘汰算法。

最佳置换(OPT)算法

选择的被淘汰页面,将是以后永不使用的,或许是在最长(未来)时间内不再被访问的页面;采用最佳置换算法可保证获得最低的缺页率。但是由于无法预知哪一个页面是未来最长时间内不再被访问的,因而该算法是无法实现的;

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

FIFO 算法是一种比较容易实现的算法。它的思想是先进先出(FIFO,队列),这是最简单、最公平的一种思想,即如果一个数据是最先进入的,那么可以认为在将来它被访问的可能性很小。空间满的时候,最先进入的数据会被最早置换(淘汰)掉

FIFO 算法的描述:设计一种缓存结构,该结构在构造时确定大小,假设大小为 K,并有两个功能:

  1. set(key,value):将记录(key,value)插入该结构。当缓存满时,将最先进入缓存的数据置换掉。
  2. get(key):返回key对应的value值。

实现:维护一个FIFO队列,按照时间顺序将各数据(已分配页面)链接起来组成队列,并将置换指针指向队列的队首。再进行置换时,只需把置换指针所指的数据(页面)顺次换出,并把新加入的数据插到队尾即可。

缺点:判断一个页面置换算法优劣的指标就是缺页率,而FIFO算法的一个显著的缺点是,在某些特定的时刻,缺页率反而会随着分配页面的增加而增加,这称为Belady现象。产生Belady现象现象的原因是,FIFO置换算法与进程访问内存的动态特征是不相容的,被置换的内存页面往往是被频繁访问的,或者没有给进程分配足够的页面,因此FIFO算法会使一些页面频繁地被替换和重新申请内存,从而导致缺页率增加。因此,现在不再使用FIFO算法

我们可以简单的用一个数组来实现FIFO,每次淘汰第一个位置的数据,每次在尾部插入即可。

LRU算法

LRU(The Least Recently Used,最近最久未使用算法)是一种常见的缓存算法,在很多分布式缓存系统(如Redis, Memcached)中都有广泛使用。

LRU算法的思想是:如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最久没有访问的数据最先被置换(淘汰)

LRU算法的描述: 设计一种缓存结构,该结构在构造时确定大小,假设大小为 K,并有两个功能:

  1. set(key,value):将记录(key,value)插入该结构。当缓存满时,将最久未使用的数据置换掉。
  2. get(key):返回key对应的value值。

实现:最朴素的思想就是用数组+时间戳的方式,不过这样做效率较低。因此,我们可以用双向链表(LinkedList)+哈希表(HashMap)实现(链表用来表示位置,哈希表用来存储和查找),在Java里有对应的数据结构LinkedHashMap,数据结构为hashMap和双向链表。

核心思想为:通过在插入的节点间建立前后连接关系,并且增加指向头尾节点的指针,实现头结点删除,尾结点写入。访问过一次移动到尾结点,这样头结点为最久未使用数据。

LInkedHashMap

 

利用JavaLinkedHashMap用非常简单的代码来实现基于LRU算法的Cache功能

import java.util.LinkedHashMap;
import java.util.Map;
/**
 * 简单用LinkedHashMap来实现的LRU算法的缓存
 */
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private int cacheSize;
    public LRUCache(int cacheSize) {
        super(16, (float) 0.75, true);
        this.cacheSize = cacheSize;
    }
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > cacheSize;
    }
}

测试:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LRUCacheTest {
	private static final Logger log = LoggerFactory.getLogger(LRUCacheTest.class);
	private static LRUCache<String, Integer> cache = new LRUCache<>(10);

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			cache.put("k" + i, i);
		}
		log.info("all cache :'{}'",cache);
		cache.get("k3");
		log.info("get k3 :'{}'", cache);
		cache.get("k4");
		log.info("get k4 :'{}'", cache);
		cache.get("k4");
		log.info("get k4 :'{}'", cache);
		cache.put("k" + 10, 10);
		log.info("After running the LRU algorithm cache :'{}'", cache);
	}
}

Output:

all cache :'{k0=0, k1=1, k2=2, k3=3, k4=4, k5=5, k6=6, k7=7, k8=8, k9=9}'
get k3 :'{k0=0, k1=1, k2=2, k4=4, k5=5, k6=6, k7=7, k8=8, k9=9, k3=3}'
get k4 :'{k0=0, k1=1, k2=2, k5=5, k6=6, k7=7, k8=8, k9=9, k3=3, k4=4}'
get k4 :'{k0=0, k1=1, k2=2, k5=5, k6=6, k7=7, k8=8, k9=9, k3=3, k4=4}'
After running the LRU algorithm cache :'{k1=1, k2=2, k5=5, k6=6, k7=7, k8=8, k9=9, k3=3, k4=4, k10=10}'

LFU算法

LFU(Least Frequently Used ,最近最少使用算法)也是一种常见的缓存算法。

顾名思义,LFU算法的思想是:如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰

LFU 算法的描述:

设计一种缓存结构,该结构在构造时确定大小,假设大小为 K,并有两个功能:

  1. set(key,value):将记录(key,value)插入该结构。当缓存满时,将访问频率最低的数据置换掉。
  2. get(key):返回key对应的value值。

LFU 算法相当于是把数据按照访问频次进行排序,这个需求恐怕没有那么简单,而且还有一种情况,如果多个数据拥有相同的访问频次,我们就得删除最早插入的那个数据。也就是说 LFU 算法是淘汰访问频次最低的数据,如果访问频次最低的数据有多条,需要淘汰最旧的数据。

算法实现策略:考虑到 LFU 会淘汰访问频率最小的数据,我们需要一种合适的方法按大小顺序维护数据访问的频率。LFU 算法本质上可以看做是一个 top K 问题(K = 1),即选出频率最小的元素,因此我们很容易想到可以用二项堆来选择频率最小的元素,这样的实现比较高效。实现策略为小顶堆+哈希表或hash表。小顶堆这里可以根据频率进行排序后,选出最小的元素进行删除

这里先给出hash表结构

class LFUCache {
    // key 到 val 的映射
    HashMap<Integer, Integer> keyToVal;
    // key 到 freq 的映射
    HashMap<Integer, Integer> keyToFreq;
    // freq 到 key 列表的映射
    HashMap<Integer, LinkedHashSet<Integer>> freqToKeys;
    // 记录最小的频次
    int minFreq;
    // 记录 LFU 缓存的最大容量
    int cap;

    public LFUCache(int capacity) {
        keyToVal = new HashMap<>();
        keyToFreq = new HashMap<>();
        freqToKeys = new HashMap<>();
        this.cap = capacity;
        this.minFreq = 0;
    }

    public int get(int key) {}

    public void put(int key, int val) {}
}

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

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

相关文章

【2023年4月美赛加赛】Z题:The future of Olympics 25页完整论文

【2023年4月美赛加赛】Z题&#xff1a;The future of Olympics 25页完整论文 1 题目 背景 国际奥委会(IOC)正面临着夏季奥运会和冬季奥运会申办数量的减少**[1]**。在过去&#xff0c;举办奥运会的竞争非常激烈&#xff0c;声望也很高。然而&#xff0c;最近&#xff0c;主办…

MySQL基础篇——MySQL数据库 表的操作,

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.表操作 1.表操作-查询创建 1&#xff09;查询当前数据库所有表 2). 查看…

在ubuntu20.x上修改mysql密码

1&#xff0c;在安装mysql后测试mysql是否安装成功可链接数据测试输入一下命令命令都在终端中输入 mysql -u root -p 提示输入密码错误 输入命令后需要输入数据库密码&#xff0c;如忘记密码可进行数据库密码的修改 2&#xff0c;sudo cat /etc/mysql/debian.cnf 输入命令后…

MySQL2-多表查询、子查询、union、limit机制

一、多表查询 在实际开发中&#xff0c;大部分情况下都不是从单表中查询数据&#xff0c;一般都是多张表联合查询取出最终的结果。一般一个业务都会对应多张表。 1.表的连接方式的分类 内连接&#xff1a;等值连接、非等值连接、自连接 外连接&#xff1a;左外连接&#xff08;…

HTML+CSS实训——Day02——写一个登陆界面

前言 今天要继续完成我们的音乐软件了&#xff0c;昨天写完了封面&#xff0c;今天该完成开屏广告和登陆界面了。 登陆界面代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-C…

00后太卷了,老油条感叹真干不过...

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&…

Whatsns内容付费seo优化带采集和熊掌号运营问答系统

正文&#xff1a; 付费课程增加付费课程试听功能基础版和高级企业版&#xff0c;Plus版增加微信消息模板回答通知&#xff0c;采纳答案通知改进兼容因导入Discuz用户密码规则不兼容导致登录失败问题基础版和高级企业版&#xff0c;Plus版增加改进微信文本回复&#xff0c;支持…

【搭建服务器】Win10 IIS搭建webdav服务以及公网访问教程 - 挂载webdav

文章目录 1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透&#xff0c;将WebDav服务暴露在公网3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表 4. 公网远程访问4.1 浏览器访问测试4.2 映射本地盘符访问4.3 安装Raidrive客户端 总结&#xff1a; 自己用W…

你真的会写测试用例吗?如何写?测试用例之中的细节拉满了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试用例中的细节…

进程间通信之system V共享内存

目录 &#x1f39e;一、共享内存---shm 1.1shmget ①ftok得到一个key ②shmget得到shm ③shm的性质 1.2 shmctl ①ipcrm ②shmctl 1.3shmat&&shmdt ①shmat ②shmdt 1.4通过shm完成进程间通信 1.5shm的特点 ①shm共享内存的优点 ②shm的缺点 1.6shm的内核…

78.建立一个Web应用程序的布局第二部分

上节课中&#xff0c;我们实现的页面如下图所示&#xff1a; 而最终的页面如下图所示&#xff1a; ● 首先我们 先添加menu的按钮 <menu><button>New</button><button>Reply</button><button>Forward</button><button>Mar…

中兴新支点操作系统电力主站和变电站安全操作系统解决方案

近日&#xff0c;由中国软件行业协会主办的“第二届中国国际软件发展大会”在北京国家会议中心成功召开&#xff0c;国家部委领导、两院院士、行业领袖、龙头企业代表等齐聚一堂&#xff0c;剖析行业热点、分享趋势前瞻。中兴新支点操作系统凭借在国网和南网广泛应用的出色表现…

彻底明白IP地址如何计算相关地址【收藏】

通过IP地址和子网掩码与运算计算相关地址&#xff0c;知道ip地址和子网掩码后可以算出&#xff1a; 1、 网络地址 2、 广播地址 3、 地址范围 4、 本网有几台主机 例1&#xff1a;下面例子IP地址为1921681005 子网掩码是2552552550。算出网络地址、广播地址、地址范围、主…

17种常见VR推广渠道,你知道几个?

随着各方面技术的成熟&#xff0c;VR内容越来越多地出现在了生活的各个角落&#xff0c;凭借其身临其境的3D沉浸式体验&#xff0c;惊艳了不少消费者&#xff0c;为线上平台、实体店铺导流变现实现了极大的价值&#xff0c;成为了当下商企最受欢迎的营销模式。 此前我们经常收…

TFM—用于实时监控和数据管理的远程试验管理平台

随着信息技术的高速发展&#xff0c;企业对远程试验实时监控与数据管理的需求日益增强。而利用远程试验信息协同技术&#xff0c;可突破部门与地域的限制&#xff0c;并把试验现场的车辆状态信息、试验数据和分析结果实时传输给数据分析部门和设计部门等&#xff0c;从而缩短时…

死锁知识记录

一、类型 一般性死锁&#xff1a;这是最经典的死锁方式。指的是多个线程的执行下必须拥有多个资源&#xff0c;但是这些资源又分别被不同的线程占有着&#xff0c;即造成了一种僵持的状态。 嵌套性死锁&#xff1a;指的就是锁的互相嵌套使用。上面这种情况的死锁类型&#xf…

自动化测试的简单认识

1.什么是自动化测试 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统&#xff0c;预设条件包括正常和异常&#xff0c;最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 2.常见的WebDriver的API 定位元素常用的是 findelement方法 比…

MySQL 锁篇

1. MySQL 有哪些锁&#xff1f; 1&#xff09;全局锁 执行后整个数据库就处于只读状态&#xff0c;一般用于全库逻辑备份 2&#xff09;表级锁&#xff1a; 表锁&#xff1a; 表级别的共享锁&#xff1a;读锁 表级别的独占锁&#xff1a;写锁 元数据锁&#xff08;MDL&am…

一文吃透 Vue 框架教程(下)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【Spring】— MyBatis配置文件元素

目录 MyBatis配置文件元素properties元素settings元素typeAliases元素typeHandler元素objectFactory元素plugins元素environments元素mappers元素 MyBatis配置文件元素 使用MyBatis框架进行开发&#xff0c;需要创建MyBatis的核心配置文件&#xff0c;该配置文件包含重要的元素…