1 、单链表在页帧管理的应用
在一些支持虚拟内存的系统中有关链表的运用,虚拟内存是一种地址空间的映射机制,它允许进程不必完全加载到物理内存中也可以得到运行。这种方式的一个突出优点就是进程可以使用比熊实际所允许的物理内存大得多的地址空间。另外一个优点是多个进程能够共享的内存以并发的方式运行。
先简单的介绍Linux操作系统存储管理方式,Linux系统采用请求式分页虚拟内存管理的方式,系统为每个进程提供了4GB的虚拟内存空间。各个进程的虚拟内存彼此独立。
那么这样运行在虚拟内存机制下的进程需要处理虚拟地址。这些地址对于虚拟内存来说就行物理内存地址一样,但是使用前必须要有操作系统做转换,由专门的硬件所支持的页表来快速执行地址的转换工作。每个进程都有自己的页表,将它的虚拟地址空间中的页映射到物理内存中的页帧上。当某个进程引用一个虚拟地址时,页表中的某项需要见车并决定页关联到那个物理的页帧上(见下图)。
页帧管理的函数的是实现
这里只介绍页帧管理中的2个重要的函数 alloc_frame free_frame。使用链表来维护可供分配的页帧,函数alloc_frame从空闲的页帧链表中货物空闲的页帧好。给定某个特定的页。将页帧号放在特定的页表中来检查该页面应对应哪个物理的页帧。当页面从物理内存中移除的时候,函数free_frame接受一个页帧号并将其放回到空闲页帧链表中。使用链表来管理页帧是一个非常好的办法,因为页帧的分配涉及到频繁的插入和删除操作,这些操作都定义在链表的头。下面为具体函数的实现,涉及到前面所定义的单链表的函数。
/*frames.c */
#include <stdlib.h>
#include "frames.h"
#include "../include/list.h"
/*alloc_frame */
int alloc_frame(List *frames,int frame_number){
int *data;
/* Allocate storage for the frame number */
if ((data = (int *)malloc(sizeof(int))) == NULL){
return -1;
}
*data = frame_number;
if(list_ins_next(frames, NULL, data) != 0){
return -1;
}
return 0;
}
int free_frame(list *frames){
int frame_number,*data;
if (list_size(frames) == 0)
return -1;
else {
if (list_rem_next(frames, NULL, (void **)& data) != 0){
return -1;
} else {
frame_number = *data;
free(data);
}
}
return frame_number;
}
2、循环链表在页面置换的用法
在上面介绍了单链表在管理页帧的分配,但还有一个问题没有搞清楚,那就是当空闲页面链表为空时,系统将如何分配新的页帧?为了解决这个问题操作系统从物理内存中取出一个页面将其放大称为交换磁盘的磁盘空间中,以这种当时来释放页帧。操作系统采用页面置换算法来决定置换在哪一个页帧在当前时刻最适合释放。页面置换算法中的一个例子是第二次机会置换法,也成为时钟算法。
第二次机会置换法是实现LRU(Least Recently Used)页面置换法的一种方式。它的工作方式是:维护一个当前存在于物理内存中的页面循环链表。假设链表中的每个元素只存储一个页码和一个引用值,引用值要么为1要么为0.在实践中,每个元素还会包含其他的信息。所有的页面初始的引用值都为0,每当系统访问页面时。该页面的应用值就设置为1.当需要某个页帧时操作系统就使用它维护的循环链表以及引用值来判断哪些页面应该释放其页帧。为了确定这一点开始遍历链表知道找到一个引用值为0的元素。当遍历每一个页面时,操作系统将页面的引用值从1重设回0.一旦它遇到的引用为0的元素,就是找到了一个上次便利链表以来都没有被系统访问的页面。就是最近很少使用的页面。
第二次页面置换算法的实现
/* page.h*/
#ifndef PAGE_H
#define PAGE_H
#include "../include/clist.h"
/*define a structuue for information about pages */
typedef struct Page_{
int number;
int reference;
}Page;
/* public Interface */
int replace_page(CListElmt **current);
#endif
/*page.c*/
#include "../include/clist.h"
#include "../include/page.h"
/*relace_page */
int replace_page(CListElmt * * current)
{
while (((Page *)(* current) ->data)->reference != 0){
((Page *)(* current) ->data)->reference = 0;
*current = clist_next(*current);
}
return ((Page *)(*current)->data->number;
}