内存管理-LRU,NFU算法实现

LRU和NFU的算法实现

(1)LRU算法实现

  LRU,汤子瀛《计算机操作系统》译为“最近最久未使用”,也即在缓冲的所有页面中,缺页中断发生时,将最久未被使用的页面置换出去。不过按照字面意思,Least Recently Used似乎应是《现代操作系统》中译版的“最近最少使用”,似乎是需要统计页面使用频率的。这里有必要先探讨下这个翻译问题。这个翻译的区别在于,副词least修饰的是recently还是used。P206原文:

A good approximation to the optimal algorithm is based on the observation that pages that have been heavily used in the last few instructions will probably be heavily used again in the next few. Conversely, pages that have not been used for ages will probably remain unused for a long time. This idea suggests a realizable algorithm: when a page fault occurs, throw out the page that has been unused for the longest time. This strategy is called LRU (Least Recently Used) paging.

  这前半段和后半段意思并不是很一致。按照前半段的意思,用的最多的(heavily used)最应该保留;而后半段,也即LRU的定义,反而是指“最久未使用”。假设这样一种情况,内存只能容纳两个页,如果考察的时间跨度大于2,对于0,0,...,0,1的页面访问序列,此时访问页面2,前半段会认为0的使用频率最高,应该保留0,而后半段认为0是最久未被使用的,应该保留1。这样就产生了矛盾。不过既然是一个近似,按后半段更合适一些,这样反而显得“最近最久未使用”是一个更合适的译法。《现代操作系统》提到的3种算法,其实都是符合定义的:

   一种实现是用一个特殊链表,将最近最多使用的放在表头,最近最少使用的放在表尾,每次使用到的页面如果在链表中,就把它取出并放到表头。不过这个实现一方面很耗时,并且实际上是“最近最久未使用”。

  一种硬件实现是使用一个计数器,每次执行指令自增1,每个页表项中提供一位来容纳这个值,每次访问时就把计数器的值存到访问的页表项中。淘汰页面时选择最小的即可。虽然很符合“最近最少使用”的含义,缺点是消耗了很多存储空间;另外,计数器的溢出也是个问题。同样是“最近最久未使用”。

  另一种硬件实现则比较精巧。对于n个页框的机器,提供一个n*n的矩阵,初始化为全0。当访问页框k时,将这个矩阵第k行全设为1,第k列全设为0,此时(k,k)是0。在任意时刻,哪一行的二进制数最小,那么它就是将被淘汰的页面。可以发现,这种做法中,最后被访问的页面会把它所在的行变为最大的(k列全为0,代表此列的大小影响不计;仅有k行全1,必然最大)。同时,页面的使用频率越高,那么它就能“保持”的较大。即使上文中探讨的作为0,0,...0,1这种序列,仍然是保持1替换0,还是“最近最久未使用”。原书对这个实现的图3-17:

  内存管理-LRU,NFU算法实现_第1张图片

(2)NFU算法实现

  LRU的实现比较复杂,而且可能需要借助特殊的硬件。一种软件实现被称为NFU(Not Frequently Used,最不常用),每个页面使用一个计数器,每次时钟中断时,将页面的R位(是否被引用,0或1)加到计数器上。缺页中断时置换计数器值最小的。

  这种实现的坏处是它“从不忘记任何事情”,简单地说就是在之前计数器值比较高的页面,即使不再访问,仍然会保持这个值;而别的页面在后续始终无法超过。对NFU做一个小修改,就可以很好的模拟LRU:将R位增加前先计数器右移、R位增加到计数器左边的最高位而不是右边的最低位。修改后的算法称为老化(aging)算法。图3-18是一个运行实例,其蕴含的特征是:越高位越新,最近的使用权重最大;早期的使用记录会随着右移而舍弃。

  内存管理-LRU,NFU算法实现_第2张图片

  从中也可看出NFU与LRU的第一个区别:对于(e),LRU只能从3和5中二选一,3和5都在2个时钟前访问过,而NFU会明确地唤出3。另一个区别是NFU只能追踪有限次(相较于LRU的前两种实现,要少一些),比如图中的8次。前第9次和前1000次的访问情况是无关紧要的。

 

你可能感兴趣的:(操作系统)