首先让我们看一道题:
在一个请求页式存储管理中,一个程序的页面走向为 4, 3, 2, 1, 3, 5, 4, 3, 2, 1, 5,并采用 LRU 算法。假设分配给该程序的存储块个数 M 分别为 3 和 4,则该访问中发生的缺页次数 F 分别是?
这里我们讲讲两个概念:
请求分页存储管理:
在进程开始前,仅装入当前要执行的部分页面即可执行;在执行过程中,可使用请求调入中断动态装入要访问但又不存在的页面;当内存空间已满,而又需要装入新的页面时,可根据置换功能适当调出页面,以便腾出空间装新的页面。
LRU算法:
Least Recently Used,及最近最久未使用
也就是说,例如在请求分页中,使用LRU管理,当内存空间已满时,就可调用算法淘汰最近一段时间内最长时间未被使用的页面。
一般建议使用双向链表+HashMap实现本算法。
先用最近常考的一道笔试题来简单实现LRU的缓存结构
上个牛客链接
代码:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
//基本思路 使用Hashmap+双向链表实现
//最近使用(进行了set/get操作)放在表头
//空间超过时,删除尾部元素
public class LRUCache {
//本代码通过80%
private int k;
private DNode head=new DNode(-1,-1);
private DNode tail=new DNode(-1,-1);
private Map<Integer,DNode> map=new HashMap<>();
public int[] LRU (int[][] operators, int k) {
this.k=k;
//链表勾连初始化
head.next=tail;
tail.prev=head;
//opt首元素为2的个数
int len = (int) Arrays.stream(operators).filter(x -> x[0] == 2).count();
int []res=new int[len];
for(int i=0,j=0;i<operators.length;i++){
if(operators[i][0]==1){//opt=1
set(operators[i][1],operators[i][2]);
}else {//opt=2
res[j++]=get(operators[i][1]);
}
}
return res;
}
private void set(int key,int val){
//先检测原key是否有值
DNode node=map.get(key);
if (node==null){
if(map.size()==k){
DNode tailnode=popTail();//拉队尾元素
map.remove(tailnode.key);
}
DNode newNode=new DNode(key,val);
map.put(key,newNode);
addNode(newNode);
}else {
node.val=val;
moveToHead(node);
}
}
private int get(int key){
if(map.containsKey(key)){
DNode node=map.get(key);
moveToHead(node);
return node.val;
}
return -1;
}
//头节点加入
public void addNode(DNode node){
node.prev=head;
node.next=head.next;
head.next.prev=node;
head.next=node;
}
//删除
//将当前结点的前后指针接在一起
public void removeNode(DNode node){
DNode prev=node.prev;
DNode next=node.next;
prev.next=next;
next.prev=prev;
}
//
private void moveToHead(DNode node){
removeNode(node);//将原结点前后指针接在一起
addNode(node);//表头添加
}
private DNode popTail(){
DNode res=tail.prev;
removeNode(res);
return res;
}
//双向链表
static class DNode{
DNode prev;
DNode next;
int val;
int key;
public DNode() {
}
public DNode(int val, int key) {
this.val = val;
this.key = key;
}
}
public static void main(String[] args) {
int[][] operators = {{1, 2, 1}, {1, 2, 2}, {1, 3, 2}, {2, 1}, {1, 4, 4}, {2, 2}};
int len = (int) Arrays.stream(operators).filter(x -> x[0] == 2).count();
System.out.println(len);
}
}
现在回头继续看那道选择题
一个程序的页面走向为 4, 3, 2, 1, 3, 5, 4, 3, 2, 1, 5,并采用 LRU 算法。假设分配给该程序的存储块个数 M 分别为 3 和 4,则该访问中发生的缺页次数 F 分别是?
M=3
请求分页管理 缺页
4 1
34 1
234 1
123 1
312 0
531 1
453 1
345 0
234 1
123 1
512 1
F=9
M=4时同理判断