详细分析置换算法

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

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

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

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

目前现代操作系统非常智能,现代操作系统大多采用局部分配的方法,这更易于操作系统控制。当操作系统开始分配页面时,会根据进程数量、进程资源大小等参数相对公平的分配固定的空间,例如总内存大小为 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.mfbz.cn/a/23024.html

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

相关文章

【MySQL学习】MySQL表的复合查询

文章目录 前言一、案例准备二、基本查询三、多表查询四、子查询4.1 单行子查询4.2 多行子查询4.3 多列子查询4.4 FROM子句中的子查询4.5 合并查询4.5.1 UNION4.5.2 UNION ALL 五、自连接六、内外连接6.1 内连接6.2 外连接6.2.1 左外连接6.2.2 右外连接 前言 对MySQL表的基本查…

【容器化应用程序设计和开发】2.7 云原生开发工具和框架

2.7 云原生开发工具和框架 今天我们就简单来讲一下云原生下用到的开发工具和一些基本的框架。云原生开发工具和框架是为了支持现代化的应用程序开发&#xff0c;能够简化云原生应用程序的构建、部署、管理和维护。下面是一些常见的云原生开发工具和框架&#xff1a; Kubernetes…

为什么别人家的ChatGPT比我家的更聪明?

文章目录 引子使用技巧技巧1&#xff1a;使用分隔符技巧2&#xff1a;结构化输出技巧3&#xff1a;整理操作步骤技巧4&#xff1a;做示范技巧5&#xff1a;给定具体的步骤技巧6&#xff1a;生成摘要技巧7&#xff1a;情感分析 好问题的三要素总结 引子 你有没有发现&#xff0…

python+Django音乐播放器网站系统0tr3w

音乐网站系统的后台开发目标是以信息管理系统的管理和开发方法&#xff0c;用目前现有的新技术进行系统开发&#xff0c;提供后台管理员高度友好的界面操作以及迅捷的信息处理。而前台的开发目标是以用户的需求作为主导&#xff0c;提供对用户而言非常友好的界面操作环境以及完…

2023年第十五届B题电工杯初步解题思路

第十五届“中国电机工程学会杯”全国大学生 电工数学建模竞赛题目 B题 人工智能对大学生学习影响的评价 人工智能简称AI&#xff0c;最初由麦卡锡、明斯基等科学家于1956年在美国达特茅斯学院开会研讨时提出。 2016年&#xff0c;人工智能AlphaGo 4:1战胜韩国围棋高手李世石…

(学习日记)AD学习 #2

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

航空公司预订票数学建模论文

航空公司预订票数学建模论文篇1 试谈机票订票模型与求解 一、概述 1. 问题背景描述 在激烈的市场竞争中&#xff0c;航空公司为争取更多的客源而开展的一个优质服务项目是预订票业务,本模型针对预订票业务&#xff0c;建立二元规划订票方案&#xff0c;既考虑航空公司的利润最大…

利用qsort排序

一、简单排序10个元素的一维数组 #define _CRT_SECURE_NO_WARNINGS #pragma warning(disable:6031) #include<stdio.h> #include<stdlib.h> void print_arr(int arr[], int sz) {int i 0;for (i 0; i < sz; i){printf("%d ", arr[i]);}printf("…

开源赋能 普惠未来|QUICKPOOL诚邀您参与2023开放原子全球开源峰会

QUICKPOOL算力调度系统的诞生和发展&#xff0c;为广大的算力领域从业者和技术开发者&#xff0c;提供了一条中国技术路线&#xff0c;并与IBM LSF、SLURM、PBS、SGE等产品&#xff0c;共同助力全球算力发展。QUICKPOOL算力调度系统成熟、稳定&#xff0c;具备“超算&智算”…

服务高可用保障:服务限流,Nginx实现服务限流

一、前言 1.1什么是限流&#xff1f; 限流存在于高可用服务中。 用于高可用的保护手段&#xff0c;主要包括&#xff1a;缓存&#xff0c;降级&#xff0c;限流 限流&#xff1a;只允许指定的事件进入系统&#xff0c;超过的部分将被拒绝服务&#xff0c;排队或者降级处理。 …

国内行业垂直型SaaS公司有哪些?发展前景如何?

01 国内行业垂直型SaaS公司有哪些&#xff1f; 根据艾瑞咨询测算&#xff0c;2021年中国企业级应用软件市场规模达到2592亿元&#xff0c;SaaS在其中占比达到28.1%。 在企业数字化转型的全景图中&#xff0c;SaaS扮演着应用场景层面的关键作用&#xff0c;往往是企业特定环节数…

ChatGPT系列学习(1)transformer基本原理讲解

文章目录 1. 简介1.1. 发展史 2. Transformer 整体结构3. 名词解释3.1. token 4. transformer输入4.1. 单词 Embedding4.2. 位置Embedding4.3. Transformer Embedding层实现 5. Attention结构5.1. 简介5.2. Self Attention&#xff08;自注意力机制&#xff09;5.2.1. 简介5.2.…

mysql 库的操作

文章目录 mysql 库的操作1. 创建数据库创建数据库案例 2. 字符集和校验规则查看系统默认的字符集合校验规则查看数据库支持的字符集查看数据库支持的字符集较验规则校验规则对数据库的影响 3. 操作数据库查看数据库显示创建语句修改数据库删除数据库查看数据库连接情况 mysql 库…

uniapp内使用 mescroll

前言 在使用uniapp开发项目的过程中&#xff0c;在很多场景里都需要下拉刷新和上拉加载&#xff0c;而 mescroll.js 则是一个非常精致的下拉刷新和上拉加载 js 框架。 官网地址&#xff1a;mescroll 介绍 mescroll.js 是在 H5端 运行的下拉刷新和上拉加载插件&#xff0c;时…

Leetcode 1679. K 和数对的最大数目 双指针法

https://leetcode.cn/problems/max-number-of-k-sum-pairs/ 给你一个整数数组 nums 和一个整数 k 。 每一步操作中&#xff0c;你需要从数组中选出和为 k 的两个整数&#xff0c;并将它们移出数组。 返回你可以对数组执行的最大操作数。 示例 1&#xff1a; 输入&#xff1…

【云计算与虚拟化】第五章—— vCenter Server 5.5 的高级功能(三)

第五章—— vCenter Server 5.5 的高级功能&#xff08;三&#xff09; 1.使用vsphere client 登陆vcenter服务器,创建一个群集&#xff0c;名称为自己的学号&#xff0c;&#xff08;截图&#xff09; 2.针对该群集打开HA功能&#xff08;截图&#xff09; 3.接入控制策略选择…

使用Python复制某文件夹下子文件夹名为数据文件夹下的所有以DD开头的文件夹到桌面...

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 楼阁玲珑五云起&#xff0c;其中绰约多仙子。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python最强王者群【魏哥】问了一个Python自动化办公处理…

单模光纤二维模场分布的MATLAB仿真

在上一篇文章中&#xff0c;我们介绍了单模光纤的一维模场分布&#xff0c;能看出沿着径向的光场分布情况&#xff0c;并分析能量的分布 这一篇中&#xff0c;我们绘制光纤横截面上的二维光场分布&#xff1a;代码如下&#xff1a; clear close all V 2.4000; U 1.6453; W …

Netty和Tomcat的区别、性能对比

文章目录 一、Netty和Tomcat有什么区别&#xff1f;二、为什么Netty受欢迎&#xff1f;三、Netty为什么并发高 &#xff1f; 一、Netty和Tomcat有什么区别&#xff1f; Netty和Tomcat最大的区别就在于通信协议&#xff0c;Tomcat是基于Http协议的&#xff0c;他的实质是一个基…

代码随想录算法训练营day52 | 300.最长递增子序列,674. 最长连续递增序列,718. 最长重复子数组

代码随想录算法训练营day52 | 300.最长递增子序列&#xff0c;674. 最长连续递增序列&#xff0c;718. 最长重复子数组 300.最长递增子序列解法一&#xff1a;动态规划 674. 最长连续递增序列解法一&#xff1a;动态规划解法二&#xff1a;双指针法 718. 最长重复子数组解法一&…
最新文章