LRU算法及实现

本文深入探讨了LRU算法的概念,包括它作为最近最少使用页面置换算法在虚拟页式存储管理中的作用。重点阐述了LRU算法如何帮助优化内存使用,以及在Oracle系统中通过链表和哈希表实现的详细步骤。此外,文章还介绍了JDK1.5中LinkedHashMap类如何实现LRU功能,并提供了线程安全的代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LRU是Least Recently Used最近最少使用算法。
   Oracle系统使用的一种算法,对于在内存中但最近又不用的数据块(内存块)叫做LRU,Oracle会根据那些数据属于LRU而将其移出内存而腾出空间来加载另外的数据。
  什么是LRU算法? LRU是Least Recently Used的缩写,即最近最少使用 页面置换算法,是为虚拟页式 存储管理服务的。
  关于操作系统的 内存管理,如何节省利用容量不大的内存为最多的进程提供资源,一直是研究的重要方向。而内存的虚拟存储管理,是现在最通用,最成功的方式—— 在内存有限的情况下,扩展一部分外存作为虚拟内存,真正的内存只存储当前运行时所用得到信息。这无疑极大地扩充了内存的功能,极大地提高了计算机的并发度。虚拟页式存储管理,则是将进程所需空间划分为多个页面,内存中只存放当前所需页面,其余页面放入外存的管理方式。
  然而,有利就有弊,虚拟页式存储管理减少了进程所需的内存空间,却也带来了运行时间变长这一缺点:进程运行过程中,不可避免地要把在外存中存放的一些信息和内存中已有的进行交换,由于外存的低速,这一步骤所花费的时间不可忽略。因而,采取尽量好的算法以减少读取外存的次数,也是相当有意义的事情。
  对于虚拟页式存储,内外存信息的替换是以页面为单位进行的——当需要一个放在外存的页面时,把它调入内存,同时为了保持原有空间的大小,还要把一个内存中页面调出至外存。自然,这种调动越少,进程执行的效率也就越高。那么,把哪个页面调出去可以达到调动尽量少的目的?我们需要一个算法。
  自然,达到这样一种情形的算法是最理想的了——每次调换出的页面是所有内存页面中最迟将被使用的——这可以最大限度的推迟页面调换,这种算法,被称为理想页面置换算法。可惜的是,这种算法是无法实现的。

编辑本段差距

  为了尽量减少与理想算法的差距,产生了各种精妙的算法,最近最少使用页面置换算法便是其中一个。LRU算法的提出,是基于这样一个事实:在前面几条指令中使用频繁的页面很可能在后面的几条指令中频繁使用。反过来说,已经很久没有使用的页面很可能在未来较长的一段时间内不会被用到。这个,就是著名的局部性原理 ——比内存速度还要快的cache,也是基于同样的原理运行的。因此,我们只需要在每次调换时,找到最近最少使用的那个页面调出内存。这就是LRU算法的全部内容。



LRU表示Least Recently Used,即最近最少被使用的页面替换算法。其理论基础是局部性原理,也就是说最近被访问的对象将在不久以后再次被访问。

 

对于LRU算法,可以使用一个链表和hashmap来实现。链表中的节点表示缓存的页面,链表中的第一个元素就是要被替换的元素,所以替换的复杂度是O(1)。同时,还维护一个hashmap来建立访问对象和缓存页面的映射关系。

 

当需要访问某个对象时,先从hashmap中查看该对象是否在缓存中,如果在,则将该缓存页面从链表中取出并插入到链表尾部,并访问对象。否则,从链表头取出一个缓存页面,将要访问的对象写入该缓存并插入到链表尾部,并且在hashmap中更新该项。这样,所有最近被访问的页面总是处于链表的尾部,即表头的元素表示最近最少被使用的可替换的页面。

 

 

LRU的实现

 

在JDK1.5中,LinkedHashMap已经实现了LRU的功能,只需要根据需要重写removeEldestEntry就行了。LinkedHashMap维护着一个运行于所有条目的双向链表。有了这个双向链表,就可以在迭代的时候按照插入的顺序迭代出元素,或者通过LRU算法迭代元素。

 

在LinkedHashMap的构造方法中,你可以指定accessOrder参数,当其为true时,将按照LRU算法对entry进行遍历;当其为false时,按照插入的顺序进行遍历。其值默认为true。想要详细了解LinkedHashMap可参见 http://boy00fly.iteye.com/blog/1144691

 

这里贴一个使用LinkedHashMap实现LRU的线程安全的代码

http://www.iteye.com/topic/123856

 

 

Java代码   收藏代码
  1. import java.util.LinkedHashMap;  
  2. import java.util.concurrent.locks.Lock;  
  3. import java.util.concurrent.locks.ReentrantLock;  
  4.   
  5. public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V>  
  6. {  
  7.     private final int maxCapacity;  
  8.     private static final float DEFAULT_LOAD_FACTOR = 0.75f;  
  9.     private final Lock lock = new ReentrantLock();  
  10.   
  11.     public LRULinkedHashMap(int maxCapacity)  
  12.     {  
  13.         super(maxCapacity, DEFAULT_LOAD_FACTOR, true);  
  14.         this.maxCapacity = maxCapacity;  
  15.     }  
  16.   
  17.     @Override  
  18.     protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest)  
  19.     {  
  20.         return size() > maxCapacity;  
  21.     }  
  22.   
  23.     @Override  
  24.     public V get(Object key)  
  25.     {  
  26.         try {  
  27.             lock.lock();  
  28.             return super.get(key);  
  29.         }  
  30.         finally {  
  31.             lock.unlock();  
  32.         }  
  33.     }  
  34.   
  35.     @Override  
  36.     public V put(K key, V value)  
  37.     {  
  38.         try {  
  39.             lock.lock();  
  40.             return super.put(key, value);  
  41.         }  
  42.         finally {  
  43.             lock.unlock();  
  44.         }  
  45.     }  
  46. }  



通过STL实现带LRU的CACHE:  http://www.cppblog.com/red22/articles/62499.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值