文章目录
页面淘汰算法模拟实现与比较
1. 实验目的
理解并掌握主要页面淘汰算法的设计和实现要旨。
2. 实验内容
利用标准 C 语言,编程设计与实现最佳淘汰算法、先进先出淘汰算法、最近最久未使用淘汰算法、简单 Clock 淘汰算法及改进型 Clock 淘汰算法,并随机发生页面访问序列开展有关算法的测试及性能比较。
3. 实验要求
本实验课题功能设计要求如下:
- 编程设计实现最佳淘汰算法OPT、先进先出淘汰算法FIFO、最近最久未使用淘汰算法LRU、简单Clock 淘汰算法及改进型 Clock 淘汰算法;
- 编程设计实现页面访问序列的随机发生机制,包括各页面读写访问方式的设定以满足改进型 Clock 淘汰算法的要求;
- 在执行进程和访问各页面过程中,每访问一个(或一次)页面应显示输出当时的进程页表内容(包括页号、物理块号、状态位、读/写访问方式等字段)及本次页面访问操作情况(譬如页面已在内存或触发缺页中断);
- 基于相同的条件,包括系统均采用固定分配局部置换策略、相同的进程逻辑地址空间大小(暨逻辑页面数,设进程逻辑地址空间的页面总数为 N,则其页号取值区间为[0, N))、分配给进程同样多的物理块(设进程分配获得 S 个物理块,则相应物理块号分别标记为 PF0、PF1、……、PFS-1)、相同的页面访问序列(整数序列,整数取值区间为[0, N))、均预装入前三个页面,进行有关算法的测试;
- 变换上述条件实施多次测试,统计分析和比较有关算法的性能(譬如缺页率、淘汰页查找时间开销)。
关于页面访问序列随机发生机制的设计思想:
- 初始化进程逻辑地址空间页面总数 N、各逻辑页面的读写访问方式(是否支持写访问,即 R、RW)、工作集起始页号 s(s∈[0, N))、工作集中包含的页数 w,工作集移动速率 v(每处理 v 个页面访问,就将工作集起始页号递增即 s+1)以及一个取值区间为[0, 1]的值 t;
- 生成取值区间为[s, min(s+w, N-1)]的 v 个随机数并添加保存到页面访问序列中,同 时为每次页面访问分别生成一个取值区间为[0, 1]的随机数,若该随机数值大于 0.7 且对应所访问页面支持写访问则设定以写方式访问相应页面,否则以读方式访问对应页面;
- 生成取值区间为[0, 1]的一个随机数 r,并比较 r 与 t 的大小;
- 若 r < t,则为 s 生成一个新值(s∈[0, N)),否则 s = (s + 1) mod N;
- 如果想继续加大页面访问序列的长度,返回第 2 步,否则结束。
4. 实验过程
4.0 整体设计
4.0.1 数据结构
- 页表结构设计
假设虚拟内存的地址是16位,页面大小为1K,则进程的大小为 2 16 = 64 K B 2^{16}=64KB 216=64KB
分页个数 = 进程的大小 页面的大小 = 逻辑地址表示的大小 页面的大小 = 2 16 B 1 K B = 2 6 页 分页个数=\frac{进程的大小}{页面的大小}=\frac{逻辑地址表示的大小}{页面的大小}=\frac{2^{16B}}{1KB}=2^{6}页 分页个数=页面的大小进程的大小=页面的大小逻辑地址表示的大小=1KB216B=26页
因此页号P占用前6位,页内偏移量W=16-6=10位。每一个页表项占用2B,因此页表存储空间需要 2 6 ∗ 2 B = 128 B 2^6*2B=128B 26∗2B=128B
页面结构以及页表项设计如下:
struct PageInfo //页面信息结构
{
int pages[MAX]; // 模拟的最大访问页面数
int isVisited; // 标志位,0表示无页面访问数据
int page_missing_num; // 缺页中断次数
int allocated_page_num; // 分配的页框数
int visit_list_length; // 访问页面序列长度
} pInfo;
struct MemInfo // 页表项信息
{
int time; //记录页框中数据的访问次数
int isVisit;//访问位
int isModify;//修改位
int pages;//页号
}mInfo;
- 关键全局变量
MemInfo pageList[MAX]; // 分配的页框
int page_loss_num = 0; // 缺页次数
int current_page; //页面访问指针
int replace_page; //页面替换指针
int is_loss_page; //缺页标志:1->缺页,0->命中
4.0.2 主要函数
Init初始化
void Init()
{
int i, pn;
is_loss_page = 0; //缺页标志,0为不缺页,1为缺页
pInfo.page_missing_num = 0; // 缺页次数
pInfo.isVisited = 0; // 标志位,0表示无页面访问数据
printf("请输入分配的页框数:"); // 自定义分配的页框数
scanf("%d", &pn);
pInfo.allocated_page_num = pn;
for (i = 0; i < MAX; i++) // 清空页面序列
{
pInfo.pages[i] = -1;
}
}
getRandomList随机生成访问序列
算法流程如下:
- 确定虚拟内存的尺寸N,工作集的起始位置p,工作集中包含的页数e,工作集移动率m(每处理m个页面访问则将起始位置p +1),
- 以及一个范围在0和1之间的值t;
- 生成m个取值范围在p和p + e间的随机数,并记录到页面访问序列串中;
- 生成一个随机数r,0 ≤ r ≤ 1;如果r < t,则为p生成一个新值,否则p = (p + 1) mod N;
- 如果想继续加大页面访问序列串的长度,请返回第2步,否则结束。
具体实现如下:
void getRandomList(int m, int e, int s)
{
int pl;
Init(); //初始化
printf("请输入访问序列的长度:");
scanf("%d", &pl); //随机生成访问序列的长度
pInfo.visit_list_length = pl;
srand((unsigned)time(NULL)); // 随机种子
int p = rand() % MAX; //在0——MAX范围内随机初始化工作集的起始位置p
int i, j=0;
double t= rand() % 10 / 10.0; // 一个范围在0和1之间的值t
for (i = 0; i < s; i++) // 重复s次
{
if (j > pInfo.visit_list_length) // 不能超过访问序列的长度
break;
for (j = i * m; j < (i + 1) * m; j++)//生成m个取值范围在p~p + e间的随机数
{
pInfo.pages[j]= (p + (rand() % e)) % MAX; //并记录到页面访问序列串中;
}
double r = (rand() % 10) / 10.0;// 生成一个范围在0-1之间的随机数r
if (r < t) // 如果r < t,则为p生成一个新值
p = rand() % MAX;
else
{
p = (p + 1) % MAX; //否则向后循环移位
}
}
}
showState跟踪显示状态信息
算法流程如下:
- 如果
current_page=0, 则说明当前页面指针处于起始位置,则首先遍历pInfo.pages[i]数组,打印页面的访问序列。其具体格式为每行显示10个等访问的页面。 - 打印当前要访问的页号
- 打印当前页框内已经有的页面号
- 通过
is_loss_page判断是否发生中断。如果发生中断,则用缺页数/已访问的页面数计算得到缺页率并显示给用户。
具体实现如下:
void showState(void)
{
int i, n;
if (current_page == 0)
{
printf("\n~~~~~~~~~~~~~~~~~页面访问序列~~~~~~~~~~~~~~~~~\n");
for (i = 0; i < pInfo.visit_list_length; i++)
{
printf("%4d", pInfo.pages[i]);
if ((i + 1) % 10 == 0) printf("\n"); //每行显示10个
}
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
}
printf("访问%3d -->内存空间[", pInfo.pages[current_page]); // 访问当前页面信息
for (n = 0; n < pInfo.allocated_page_num; n++) // 页框信息
{
if (pageList[n].pages >= 0)
printf("%3d", pageList[n].pages);
else
printf(" ");
}
printf(" ]");
if (is_loss_page == 1) //缺页标志,0为不缺页,1为缺页
{
printf(" --> 缺页中断 --> ");
if (current_page == 0)
{
printf("缺页率 = %3.1f", (float)(pInfo.page_missing_num) * 100.00 );
}
else{
printf("缺页率 = %3.1f", (float)(pInfo.page_missing_num) * 100.00 / current_page); }
}
printf("\n");
}
isExist查找页面是否已经在内存中
算法流程如下:
- 遍历所有在内存中的页面,同时使得访问次数加1
- 然后再次遍历内存,寻找匹配页号的页表项
- 如果找到该页表项,则置
is_loss_page缺页标志=0(不缺页),同时访问次数time也置为0,然后通过随机生成的0或者1,来设置该访问页面是否被修改。并返回1。 - 如果没有找到该页面,则缺页中断的次数+1,同时返回0。
int isExist(int page)
{
int n;
for (n = 0; n < pInfo.allocated_page_num; n++)
pageList[n].time++; // 访问次数加1
for (n = 0; n < pInfo.allocated_page_num; n++)
{
if (pageList[n].pages == page)
{
is_loss_page = 0; //is_loss_page缺页标志=0(不缺页)
pageList[n].time = 0; //置访问次数为0
pageList[n].isVisit = 1; // 访问标志
if (randBool()) {
pageList[n].isModify = 1; // 修改标志
}
return 1;
}
}
is_loss_page = 1; //页面不存在,缺页
return 0;
}
其中调用了randBool()函数,随机的生成0或者1,其具体实现如下
bool randBool()
{
if ((rand() % 2 + 1) == 1)
return true;
else
return false;
}
4.1 最佳淘汰算法(OPT)
4.1.1 原理介绍
算法规则:选择永不使用或是在最长时间内不再被访问(即距现在最长时间才会被访问)的页面淘汰出内存。
假定系统为某进程分配了三个物理块,并考虑有以下页面访问序列:
[7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1]
进程运行时,先将7, 0, 1三个页面依次装入内存。进程要访问页面2时,产生缺页中断,根据最佳置换算法,选择第18次访问才需调入的页面7予以淘汰。然后,访问页面0时,因为已在内存中所以不必产生缺页中断。访问页面3时又会根据最佳置换算法将页面1淘汰……依此类推。
| 页面 | 7 | 0 | 1 | 2 | 0 | 3 | 0 | 4 | 2 | 3 | 0 | 3 | 2 | 1 | 2 | 0 | 1 | 7 | 0 | 1 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 页面1 | 7 | 7 | 7 | 2 | 2 | 2 | 2 | 2 | 7 | |||||||||||
| 页面2 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | ||||||||||||
| 页面3 | 1 | 1 | 3 | 3 | 3 | 1 | 1 | |||||||||||||
| 缺页 | √ | √ | √ | √ | √ | √ | √ | √ |
4.1.2 代码实现
算法流程图如下:

OPT 算法具体实现如下:
void OPT()
{

本文详细介绍了操作系统中五种常见的页面置换算法——最佳淘汰算法(OPT)、先进先出淘汰算法(FIFO)、最近最久未使用淘汰算法(LRU)、简单Clock淘汰算法(NRU)及其改进版。通过C语言实现,模拟了随机页面访问序列,并对比了它们的缺页率和性能。实验结果显示,最优算法的缺页率最低,而FIFO算法的缺页率最高。此外,还探讨了不同算法的实现思想和优缺点。
—— 页面淘汰算法模拟实现与比较&spm=1001.2101.3001.5002&articleId=125444746&d=1&t=3&u=3d038c5d0f594d479a96eb9e40bb71ed)
1127

被折叠的 条评论
为什么被折叠?



