操作系统课程设计.docx
《操作系统课程设计.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计.docx(15页珍藏版)》请在冰豆网上搜索。
操作系统课程设计
操作系统课程设计实验
WRK内存管理试验
姓名:
莫金博
班级:
08级计算机1班
学号:
20086789
一.实验内容描述
1.目的
(1)了解Windows内存管理器
(2)理解Windows的地址过程
2.内容
任意给出一个虚拟地址,通过WinDbg观察相关数据并找到其物理地址
二.理论分析
Windows采用页式虚拟存储管理技术管理内存,页面是硬件级别上的最小保护单位
1.Windows内存管理器
Windows的内存管理主要由Windows执行体中的虚存管理程序负责,并由环境子系统负责,并由环境子系统负责与具体API相关的一些用户态特性的实现。
虚存管理程序是Windows中负责内存管理的那些子程序和数据结构的集合
内存管理器的主要任务是:
地址变换:
将一个进程的虚拟地址空间转译为物理内存地址
交换:
当内存不足时,将内存中的有些内容转移到磁盘上,并且以后还要再次将这些内容读回
2.Windows内存管理策略
Windows采用页式虚拟存储管理技术管理内存,页面是硬件级别上最小的保护单位。
根据硬件的体系结构不同,页面尺寸被分为两种,大页面和小页面。
X86系统下小页面为4KB,大页面为4MB。
大页面的优点是:
当引用同一页面内其他数据时,地址转移的速度会很快。
不过使用大页面通常要较大的内存空间,而且必须用一个单独的保护项来映射,因此可能会造成出现错误而不引发内存访问违例的情况。
通常PC机都为小页面
3.Windows虚拟地址空间布局
x86结构下的布局方式:
默认情况下,32位Windows系统中每个用户进程可以占有2GB的私有地址空间。
操作系统占有另外的2GB
2GB用户的进程地址空间布局如表:
2GB的系统地址空间布局如同:
3.虚拟地址转译
地址转译是指将进程的虚拟地址空间映射到实际物理页面的过程。
x86系统中地址转译过程如图:
关键数据结构如下:
页目录:
每个进程都有一个页目录,它是内存管理器为了映射进程中所有的页表位置而创建的一个页面。
进程也目录的地址被保存在内核进程快KPROCESS中,在x86系统上,它被映射到虚拟地址0xC0300000,当一个进程正在执行时,CPU可以通过寄存器CR3知道该进程页目录的位置。
页目录由目录项(PDE)构成,每个PDE长4字节,描述了该进程中所有可能的页表的状态和位置。
其格式和PTE类似。
x86系统上,要描述完整的4GB虚拟地址空间,需要1024个页表。
因此映射这些页表的进程页目录需包含1024个PDE,恰好占用一个页面。
页表:
进程的页目录项指向页表。
每个页表占用一个页面,由1024项PTE组成。
一个有效的PTE大小为4字节,包含两个主域:
数据所在的物理页面的页面帧编号(PNF)或者内存中一个页面的物理地址的PFN;一些描述该页面状态和保护属性的标志。
虚拟地质结构:
x86系统上,一个32位虚拟地址被解释为三个单独的部分,页目录索引、页表索引和字节索引。
由于页目录项有1024个,因此页目录索引为10位;一个也表中含有1024个PTE。
因此页表索引也为10位,字节索引为12位,正好表示一页(4KB)内容
三.实验步骤及结果
1.查找页目录首地址
以程序WG.exe作为观测对象。
启动WinDbg到内核调试模式,运行程序WG.exe。
终断目标机运行,输入命令:
kd>!
process
发现WG.exe进程正处于运行状态
输入命令:
在KPROCESS中名为DirectoryTableBase的域,对应值为0x9fa6000,即WG.exe进程页目录的物理地址
查看CR3寄存其中的内容,输入命令:
CR3寄存其中的值和KPROCESS中记录的页目录基址相同。
这是因为在CPU切换执行任务时,其内容要更新为当前进程的页目录基址。
2.地址转译过程
假设给定的虚拟地址为0x401001
输入命令:
可以看到:
PDE的虚拟地址为C0300004.
PTE的虚拟地址为C0001004
最后一行信息“pfn9e4a---DA--UWEV”表示PDE中的具体内容,9e4a是给定虚拟地址所在页表在内存中对应的物理页号,“---DA—UWEV”是标志信息,“pfna173----A--UREV”表示PTE中的具体内容,a173是数据页装入内存的物理页号。
将数据页对应的物理页号a173加上业内索引(0x1)即可得到虚拟地址0x401001的物理地址
3.观察系统页表
给定观测虚拟地址为0x80001001
输入命令:
当前正在执行的进程是:
WG.exe
输入命令:
得到PDE为C0300800,其对应的物理页号为3b
继续让目标机运行,启动A.exe,然后中断目标机运行。
输入命令:
当前正在执行的进程为A.exe
输入命令:
PDE信息和对应的物理页号与前面观测到的相同
四.结论
1.数据页对应的物理页号加上相应业内索引即可得到虚拟地址的物理地址
2.不同的进程页目录都指向了相同的系统表页
五.心得体会
在这次上机实验,通过对WinDbg和VPc的调试运用,我熟悉了Windows内存管理器的结构,也认知到Windows如何进行地址转译和转换。
对相关的知识也进行了温习,更牢的掌握了相关知识。
当然这些还远远不够,我以后还要继续不断努力,去学习了解掌握操作系统的各方面知识。
附录:
1.A.exe代码
#include
#include
#defineN1
HANDLEmutexSemaphore;
HANDLEsynchSemaphore_1;
HANDLEsynchSemaphore_2;
HANDLEmutexDisplay;
voidDisplay(char*str,intdelayTime)
{
if(WaitForSingleObject(mutexDisplay,INFINITE)==WAIT_OBJECT_0)
{
printf("%s\n\n",str);
ReleaseMutex(mutexDisplay);
Sleep(delayTime);
}
}
voiduseTime(doublelimit)
{
for(doublei=0;i<=limit;i+=0.001);
}
voidCreateProduct()
{
Display("Creatingaproduction...",0);
useTime(200000);
Display("Creatingfinished.",100);
}
voidPutProduct()
{
Display("Puttingaproduction...",0);
useTime(150000);
Display("Puttingfinished",100);
}
voidGetProduct()
{
Display("Gettingaproduction...",0);
useTime(100000);
Display("Gettingfinished.",100);
}
voidConsumeProduct()
{
Display("Cosumingaproduction...",0);
useTime(100000);
Display("Cosumingfinished.",100);
}
voidProducer()
{
while(true)
{
CreateProduct();
if(WaitForSingleObject(synchSemaphore_1,INFINITE)==WAIT_OBJECT_0)
{
if(WaitForSingleObject(mutexSemaphore,INFINITE)==WAIT_OBJECT_0)
{
PutProduct();
ReleaseSemaphore(mutexSemaphore,1,NULL);
}
ReleaseSemaphore(synchSemaphore_2,1,NULL);
}
}
}
voidConsumer()
{
while(true)
{
if(WaitForSingleObject(synchSemaphore_2,INFINITE)==WAIT_OBJECT_0)
{
if(WaitForSingleObject(mutexSemaphore,INFINITE)==WAIT_OBJECT_0)
{
GetProduct();
ReleaseSemaphore(mutexSemaphore,1,NULL);
}
ReleaseSemaphore(synchSemaphore_1,1,NULL);
}
ConsumeProduct();
}
}
intmain()
{
HANDLEthread[2];
DWORDthreadID[2];
synchSemaphore_1=CreateSemaphore(NULL,N,N,NULL);
synchSemaphore_2=CreateSemaphore(NULL,0,N,NULL);
mutexSemaphore=CreateSemaphore(NULL,1,1,NULL);
mutexDisplay=CreateMutex(NULL,FALSE,NULL);
printf("Programstart.PleaseuseWinDbgtoobservemainthread.\nPressanykeytocontinue...\n");
getchar();
thread[0]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Producer),NULL,CREATE_SUSPENDED,&threadID[0]);
printf("Aproducerwascreated.PleaseuseWinDbgtoobserveproducerthread.\nPressanykeytocontinue...\n");
getchar();
thread[1]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consumer),NULL,CREATE_SUSPENDED,&threadID[1]);
printf("AConsumerwascreated.PleaseuseWinDbgtoobserveConsumerthread.\nPressanykeytocontinue...\n");
getchar();
printf("Pleaseselect:
\n[1]Makeproducerthreadrun\n[2]MakeConsumerthreadrun\n");
boolflag=true;
boolflag_1=true,flag_2=true;
intcount=0;
while(flag)
{
if(getchar()=='1'&&flag_1)
{
ResumeThread(thread[0]);
count++;
flag_1=false;
}
elseif(getchar()=='2'&&flag_2)
{
ResumeThread(thread[1]);
count++;
flag_2=false;
}
if(count==2)
flag=false;
}
WaitForMultipleObjects(1,thread,TRUE,INFINITE);
return0;
}
2.WG.exe代码:
#include
intmain()
{
inta=0;
printf("I'mWang\n");
while(true)
{a++;}
}