实验目的
- (1)了解内存管理的概念,掌握分页、分段操作过程。
- (2)掌握虚拟内存技术的概念,重点理解替换策略。
- (3)理解选择替换页算法OPT、FIFO、LRU、CLOCK。
实验内容
(用户态)在Linux下编程实现虚存页面替换算法的模拟程序。
实验环境
Ubuntu 12.04 LTS
Device name: oslinux-virtual-machine
Memory: 1001.2MiB
Processor: AMD Ryzen 77730U with Radeon Graphics
Graphics: Unknown
OS type: 32-bit
Disk: 20.3GB
实验步骤
- (1)根据用户输入参数,包含进程大小(页数),进程地址(页地址)顺 序,驻留集大小。
- (2)验证test5.c中FIFO、LRU替换算法。
- (3)新建工程replace,编写并运行CLOCK和OPT算法。
5.实验结果
对test5.c中FIFO、LRU替换算法的验证
可以看到,当使用的是FIFO算法时,当第一次page fault时,将page1换出,并换入page2;当第二次page fault时,将page4换出,并换入page1;当第三次page fault时,将page0换出,并换入page4;当第四次page fault时,将page2换出,并换入page3 。由此可见,总是最先进入的页被换出,符合FIFO先进先出算法。
可以看到,当使用LRU算法时,每当遇到page fault时,总是保留之前最近几次访问过的几个page,并将驻留集中最久没有访问过的page换出,然后换入当前需要的page,符合LRU算法。
CLOCK和OPT算法运行结果
核心代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define random(x) (rand() % x)
#define MULTIPLE 3
typedef struct page_s //页的数据结构
{
int n; // number
int v; // visit flag
} page;
char *menu[] = {
"c - CLOCK",
"o - OPT",
"q - QUIT",
NULL};
int getchoice(char *greet, char *choices[]) //实现菜单选择功能
{
int chosen = 0;
int selected;
char **option;
do
{
printf("Choice: %s\n", greet);
option = choices;
while (*option)
{
printf("%s\n", *option);
option++;
}
do
{
selected = getchar();
} while (selected == '\n');
option = choices;
while (*option)
{
if (selected == *option[0])
{
chosen = 1;
break;
}
option++;
}
if (!chosen)
{
printf("Incorrect choice, select again\n");
}
} while (!chosen);
return selected;
}
void buildPageReference(int size, page **reference, page *program)
{
int i;
int n;
printf("Page reference : ");
for (i = 0; i < size; i++)
{
n = random(size / MULTIPLE);
reference[i] = &program[n]; //随机取一个进程的页放进预分配数组中
program[n].n = n;
program[n].v = 0;
printf("| %d ", n);
}
printf("\n");
}
void print(int n, page *frame, int size)
{
int i;
printf("no. %d step: ", n);
for (i = 0; i < size; i++)
{
printf("| %d ", frame[i].n);
}
printf("\n");
}
int Search(int n, page *list, int size)
{
int i;
for (i = 0; i < size; i++)
{
if (list[i].n == n)
return i;
}
return -1;
}
int findNext(int n, page **list, int start, int size)
{
int count = size;
int i;
for (i = start; i < size; i++)
{
if (list[i]->n == n)
break;
else
count++;
}
return count;
}
int findLastMax(page *frame, int size)
{
int tmp = 0, s, i, j = 0;
for (i = 0; i < size; i++)
{
s = frame[i].v;
if (s > tmp)
{
tmp = s;
j = i;
}
}
return j;
}
int findLastMin(page *frame, int size)
{
int tmp = frame[0].v, s, i, j = 0;
// printf("| %d ", tmp);
for (i = 1; i < size; i++)
{
s = frame[i].v;
// printf("| %d ", s);
if (s < tmp)
{
tmp = s;
j = i;
}
}
// printf("\n");
return j;
}
void opt(int fsize, page *frame, int rsize, page **pageR)
{
int i, j, p = 0, q;
int f = 0; //记录page fault,缺页中断
for (i = 0; i < fsize; i++)
{
frame[i].n = -1;
frame[i].v = 0;
}
for (i = 0; i < rsize; i++)
{
q = Search(pageR[i]->n, frame, fsize);
if (q != -1) //三段式,先判断是否已经有这个页,有直接访问,若无再判断是否有新页框,若都没有再开始本算法
;
else if (i < fsize || p < fsize)
{
frame[p].n = pageR[i]->n; //有未使用的页框,直接访问
p++;
}
else
{
for (j = 0; j < fsize; j++)
{
frame[j].v = findNext(frame[j].n, pageR, i, rsize); //迭代更新v值,即计算下次找到该页时的间距
}
q = findLastMax(frame, fsize); //普通的顺序查找算法,找出最长的间隔时间的页框(用v值比较)
frame[q].n = pageR[i]->n;
f++;
}
print(i, frame, fsize);
}
printf("page fault : %d\n", f);
}
void clk(int fsize, page *frame, int rsize, page **pageR)
{
int i, j = 0, p = 0,q;
int f = 0; //记录page fault,缺页中断
for (i = 0; i < fsize; i++)
{
frame[i].n = -1;
frame[i].v = 0;
}
for (i = 0; i < rsize; i++)
{
if (q = Search(pageR[i]->n, frame, fsize) != -1) //三段式,先判断是否已经有这个页,有直接访问,若无再判断是否有新页框,若都没有再开始本算法
frame[q].v = 1;
else if (i < fsize || p < fsize)
{
frame[p].n = pageR[i]->n;
frame[p].v = 1;
j++;
p++;
}
else
{
while (1)
{
if (frame[j % fsize].v == 0) //类似于FIFO,但是多了1位v,用于在触发缺页中断时标记该页框是否已被访问过
{
frame[j % fsize].n = pageR[i]->n;
frame[j % fsize].v = 1;
j++; // j维护循环队列指向
f++;
break;
}
else
{
frame[j % fsize].v = 0;
j++; // j维护循环队列指向
}
}
}
print(i, frame, fsize);
}
printf("page fault : %d\n", f);
}
int main()
{
int choice = 0;
int logSize; //逻辑内存大小
int phySize; //物理内存大小(实际的页框)
page *program;
page **pageR;
page *frame;
int prSize;
srand((int)time(0));
printf("Enter number of pages in program: ");
scanf("%d", &logSize);
printf("Enter number of frames in physical memory: ");
scanf("%d", &phySize);
program = (page *)malloc(sizeof(int) * 2 * logSize);
frame = (page *)malloc(sizeof(int) * 2 * phySize);
prSize = logSize * MULTIPLE; //预分配逻辑内存大小
pageR = (page **)malloc(sizeof(int *) * prSize); //预分配逻辑内存
buildPageReference(prSize, pageR, program); //初始化预分配逻辑内存的数组
do
{
choice = getchoice("Please select an action", menu);
printf("You have chosen: %c\n", choice);
switch (choice)
{
case 'o':
opt(phySize, frame, prSize, pageR);
break;
case 'c':
clk(phySize, frame, prSize, pageR);
break;
default:
break;
}
} while (choice != 'q');
exit(0);
}