物理存储器与进程逻辑地址空间的管理.docx
《物理存储器与进程逻辑地址空间的管理.docx》由会员分享,可在线阅读,更多相关《物理存储器与进程逻辑地址空间的管理.docx(12页珍藏版)》请在冰豆网上搜索。
物理存储器与进程逻辑地址空间的管理
实验6物理存储器与进程逻辑地址空间的管理
实验性质:
验证+设计
建议学时:
2学时
一、实验目的
●通过查看物理存储器的使用情况,并练习分配和回收物理内存,从而掌握物理存储器的管理方法。
●通过查看进程逻辑地址空间的使用情况,并练习分配和回收虚拟内存,从而掌握进程逻辑地址空间的管理方法。
二、预备知识
阅读本书第6章。
重点阅读第6.3节和第6.6节,了解物理存储器的管理方式和进程逻辑地址空间的管理方式。
三、实验内容
3.1准备实验
按照下面的步骤准备实验:
1.启动OSLab。
2.新建一个EOSKernel项目。
3.2阅读控制台命令“pm”相关的源代码,并查看其执行的结果
阅读ke/sysproc.c文件中第1059行的ConsoleCmdPhysicalMemory函数,学习“pm”命令是如何统计并输出物理存储器信息的。
在阅读的过程中需要注意下面几点:
●在统计输出物理存储器信息之前要关闭中断,之后要打开中断,这样可以防止在命令执行的过程中有其它线程分配或者释放物理页。
●全局变量MiTotalPageFrameCount保存了物理页的总数。
每个物理页的大小是4KB,由宏PAGE_SIZE定义。
●全局变量MiZeroedPageCount和MiFreePageCount分别保存了零页和空闲页的数量。
●计算已用物理页数量的方法是:
物理页总数减去零页数量,再减去空闲页数量。
按照下面的步骤执行控制台命令“pm”,查看物理存储器的信息:
1.按F7生成在本实验3.1中创建的EOSKernel项目。
2.按F5启动调试。
3.待EOS启动完毕,在EOS控制台中输入命令“pm”后按回车。
观察命令执行的结果,如图15-1所示,可以了解当前物理存储器的使用情况。
图15-1:
“pm”命令的执行结果
3.3分配物理页和释放物理页
接下来,在pm命令函数中添加分配物理页和释放物理页的代码,单步调试管理物理页的方法。
按照下面的步骤修改pm命令的源代码:
1.使用OSLab打开本实验文件夹中的pm.c文件(将文件拖动到OSLab窗口中释放即可打开)。
此文件中有一个修改后的ConsoleCmdPhysicalMemory函数,主要是在原有代码的后面增加了分配物理页和释放物理页的代码。
2.使用pm.c文件中ConsoleCmdPhysicalMemory函数的函数体替换ke/sysproc.c文件中ConsoleCmdPhysicalMemory函数的函数体。
3.按F7生成修改后的EOSKernel项目。
4.按F5启动调试。
5.待EOS启动完毕,在EOS控制台中输入命令“pm”后按回车。
观察命令执行的结果,如图15-2所示,尝试说明分配物理页或者释放物理页后物理存储器的变化情况。
图15-2:
分配物理页或者释放物理页后物理存储器的变化情况
按照下面的步骤调试分配物理页和释放物理页的过程:
1.结束之前的调试。
2.在ke/sysproc.c文件的ConsoleCmdPhysicalMemory函数中,在调用MiAllocateAnyPages函数的代码行(第1103行)添加一个断点,在调用MiFreePages函数的代码行(第1115行)添加一个断点。
3.按F5启动调试。
4.待EOS启动完毕,在EOS控制台中输入命令“pm”后按回车。
5.pm命令开始执行后,会在调用MiAllocateAnyPages函数的代码行处中断,按F11调试进入MiAllocateAnyPages函数。
6.按F10单步调试MiAllocateAnyPages函数的执行过程,尝试回答下面的问题:
(1)本次分配的物理页的数量是多少?
分配的物理页的页框号是多少?
(2)物理页是从空闲页链表中分配的?
还是从零页链表中分配的?
(3)哪一行语句减少了空闲页的数量?
哪一行语句将刚刚分配的物理页由空闲状态修改为忙状态?
(4)绘制MiAllocateAnyPages函数的流程图。
继续调试释放物理页的过程:
1.按F5继续执行,会在调用MiFreePages函数的代码行处中断,按F11调试进入MiFreePages函数。
2.按F10单步调试MiFreePages函数的执行过程,尝试回答下面的问题:
(1)本次释放的物理页的数量是多少?
释放的物理页的页框号是多少?
释放的物理页是之前分配的物理页吗?
(2)释放的物理页是被放入了空闲页链表中?
还是零页链表中?
(3)绘制MiFreePages函数的流程图。
结束此次调试。
继续修改pm命令的源代码,尝试在调用MiAllocateAnyPages函数时分配多个物理页,然后在调用MiFreePages函数时将分配的多个物理页释放,并练习调试这两个函数在分配多个物理页和释放多个物理页时执行的过程。
3.4阅读控制台命令“vm”相关的源代码,并查看其执行的结果
阅读ke/sysproc.c文件中第959行的ConsoleCmdVM函数,学习“vm”命令是如何统计并输出进程的虚拟地址描述符信息的。
在阅读的过程中需要注意下面几点:
●与“pm”命令输出的是整个系统的物理存储器的使用情况不同,“vm”命令输出的是某个进程的虚拟地址描述符信息,所以“vm”命令使用了一个参数——进程ID,用来指定一个进程。
这个进程既可以是系统进程,也可以是用户进程。
●在统计输出指定进程的虚拟地址描述符信息之前要关闭中断,之后要打开中断,这样可以防止在命令执行的过程中有其它线程分配或者释放虚拟页。
●EOS操作系统的进程有4G的虚拟地址空间,但并不是所有的虚拟地址空间都使用虚拟地址描述符来管理,有一些地址空间是静态的,还有一些地址空间由其他的动态方式来管理(例如系统内存池)。
●进程4G虚拟地址空间中由虚拟地址描述符所管理空间的低地址和高地址是固定的,在这段地址空间中,如果有虚拟页被占用,就会使用虚拟地址描述符来标识,并放入链表中管理。
按照下面的步骤执行控制台命令“vm”,查看系统进程的虚拟地址描述符信息:
1.按F5启动调试。
2.待EOS启动完毕,在EOS控制台中输入命令“pt”后按回车。
“pt”命令可以输出当前系统中的进程列表,其中系统进程的ID为1。
3.在EOS控制台中输入命令“vm1”后按回车。
观察命令执行的结果,如图15-3所示,可以了解系统进程的虚拟地址描述符信息。
图15-3:
使用“vm”命令查看系统进程虚拟地址描述符的结果
系统进程中由虚拟地址描述符所管理的虚拟页只会分配给进程的句柄表(句柄表占用一个虚拟页)和线程的堆栈(堆栈占用两个虚拟页)。
结合之前“pt”命令输出的进程和线程信息可知,当前系统中只有1个系统进程以及10个系统线程,所以在图15-3中,1号描述符所包含的一个虚拟页即为系统进程的句柄表,而2到11号这10个描述符所分别包含的两个虚拟页即为10个系统线程的堆栈。
可以按照下面的步骤执行控制台命令“vm”,查看当创建了一个应用程序进程后,系统进程和应用程序进程中虚拟地址描述符的信息:
1.在“项目管理器”窗口中双击Floppy.img文件,使用FloppyImageEditor工具打开此软盘镜像。
2.将本实验文件夹中的LoopApp.exe文件添加到软盘镜像的根目录中(将LoopApp.exe文件拖动到FloppyImageEditor窗口中释放即可)。
EOS应用程序LoopApp.exe的源代码可以参考本实验文件夹中的LoopApp.c文件。
3.点击FloppyImageEditor工具栏上的保存按钮,关闭该工具。
4.按F5启动调试。
5.待EOS启动完毕,在EOS控制台中输入命令“A:
\LoopApp.exe”后按回车。
此时就使用EOS应用程序文件LoopApp.exe创建了一个应用程序进程,由于此进程执行了一个死循环,所以此进程不会结束执行,除非关闭虚拟机。
6.此时按Ctrl+F2切换到“Console-2”,然后输入命令“pt”后按回车。
输出的信息如图15-4所示。
其中ID为31的进程就是应用程序进程,ID为33的线程就是应用程序进程的主线程。
7.输入命令“vm1”后按回车,可以查看系统进程中虚拟地址描述符的信息。
输出的信息如图15-5所示。
与图15-3比较可知,3号描述符所包含的一个虚拟页即为应用程序进程的句柄表,13号
描述符所包含的两个虚拟页即为应用程序进程主线程的堆栈。
8.输入命令“vm31”后按回车,可以查看应用程序进程中虚拟地址描述符的信息。
输出的信息如图15-6所示。
图15-4:
使用pt命令查看有应用程序运行时进程和线程的信息
图15-5:
创建了一个应用程序进程后,系统进程中虚拟地址描述符的信息
图15-6:
使用“vm”命令查看应用程序进程虚拟地址描述符的结果
在进程的4G逻辑地址空间中,应用程序进程可以自行管理低2G的用户空间。
从图15-6中的信息可以得知,低2G的用户空间又被分为了三部分:
●0x00000000-0x0000FFFF由16个虚拟页构成的64KB静态空间,用于捕捉对空指针的非法访问。
●0x00010000-0x7FFEFFFF由虚拟地址描述符管理的动态空间,用于存储应用程序进程的代码和数据。
图15-6显示应用程序进程的代码和数据占用了此空间中的5个虚拟页,并且是用从应用程序的基址0x00400000起始的。
●0x7FFF0000-0x7FFFFFFF由16个虚拟页构成的64KB静态空间,用于捕捉对空指针的非法访问。
为了加深对进程逻辑地址空间的理解,可以在控制台1至控制台7中都执行命令“A:
\LoopApp.exe”,从而让应用程序创建7个进程,然后在控制台8中执行“pt”、“vm”等命令,查看系统进程和应用程序进程的虚拟地址描述符。
3.5在系统进程中分配虚拟页和释放虚拟页
接下来,在vm命令函数中添加分配虚拟页和释放虚拟页的代码,单步调试管理虚拟页的方法。
首先,按照下面的步骤修改vm命令的源代码:
1.使用OSLab打开本实验文件夹中的vm.c文件(将文件拖动到OSLab窗口中释放即可打开)。
此文件中有一个修改后的ConsoleCmdVM函数,主要是在原有代码的后面增加了分配虚拟页和释放物理页的代码。
2.使用vm.c文件中ConsoleCmdVM函数的函数体替换ke/sysproc.c文件中ConsoleCmdVM函数的函数体。
3.按F7生成修改后的EOSKernel项目。
4.按F5启动调试。
5.待EOS启动完毕,在EOS控制台中输入命令“vm1”后按回车。
命令执行的结果会同时转储在“输出”窗口中,内容如图15-7所示。
尝试说明分配虚拟页或者释放虚拟页后虚拟地址描述符以及物理存储器的变化情况。
图15-7:
分配虚拟页或者释放虚拟页后虚拟地址描述符及物理存储器的变化情况
按照下面的步骤调试分配虚拟页和释放虚拟页的过程:
1.在ke/sysproc.c文件的ConsoleCmdVM函数中,在调用MmAllocateVirtualMemory函数的代码行(第1082行)添加一个断点,在调用MmFreeVirtualMemory函数的代码行(第1147行)添加一个断点。
2.按F5启动调试。
3.待EOS启动完毕,在EOS控制台中输入命令“vm1”后按回车。
4.vm命令开始执行后,会在调用MmAllocateVirtualMemory函数的代码行处中断。
此时要注意参数BaseAddress和RegionSize初始化的值。
按F11调试进入MmAllocateVirtualMemory函数。
5.按F10单步调试MmAllocateVirtualMemory函数的执行过程,尝试回答下面的问题:
(1)分配的虚拟页的起始地址是多少?
分配的虚拟页的数量是多少?
它们和参数BaseAddress和RegionSize初始化的值有什么样的关系?
(2)分配虚拟页的同时有为虚拟页映射实际的物理页吗?
这是由哪个参数决定的?
(3)分配的虚拟页是在系统地址空间(高2G)还是在用户地址空间(低2G)?
这是由哪个参数决定的?
(4)参考MiReserveAddressRegion函数的定义和注释,说明该函数的功能。
继续调试释放虚拟页的过程:
1.按F5继续执行,会在调用MmFreeVirtualMemory函数的代码行处中断。
此时要注意参数BaseAddress和RegionSize初始化的值。
按F11调试进入MmFreeVirtualMemory函数。
2.按F10单步调试MmFreeVirtualMemory函数的执行过程,尝试回答下面的问题:
(1)本次释放的虚拟地址是多少?
释放的虚拟页是之前分配的虚拟页吗?
(2)参考MiFindReservedAddressRegion函数、MiFreeAddressRegion函数和MiDecommitPages函数的定义和注释,说明这些函数的功能。
结束此次调试后,继续按照下列要求修改ConsoleCmdVM函数的源代码,加深对虚拟页分配和释放过程的理解:
1.尝试在调用MmAllocateVirtualMemory函数时将RegionSize参数的值设置为PAGE_SIZE+1或者PAGE_SIZE*2+1。
观察“输出”窗口中转储的信息,并说明申请虚拟内存的大小与实际分配的大小之间的关系,以及分配的虚拟内存大小会对分配的虚拟地址产生什么样的影响。
将“输出”窗口中转储的信息保存在文本文件中。
2.尝试在调用MmAllocateVirtualMemory函数时将BaseAddress参数的值设置为已经被占用的虚拟内存,例如0xA0000000,观察“输出”窗口中转储的信息。
将“输出”窗口中转储的信息保存在文本文件中。
3.尝试在调用MmAllocateVirtualMemory函数时将RegionSize参数的值设置为PAGE_SIZE*2,将BaseAddress参数的值设置为0xA0017004,观察“输出”窗口中转储的信息,并说明申请虚拟内存的大小与实际分配的大小之间的关系,以及申请的虚拟地址会对分配的虚拟内存大小产生什么样的影响。
将“输出”窗口中转储的信息保存在文本文件中。
3.6在应用程序进程中分配虚拟页和释放虚拟页
3.6.1要求
创建一个EOS应用程序,并编写代码完成下列功能:
1.调用API函数VirtualAlloc,分配一个整型变量所需的空间,并使用一个整型变量的指针指向这个空间。
2.修改整型变量的值为0xFFFFFFFF。
在修改前输出整型变量的值,在修改后再输出整型变量的值。
3.调用API函数Sleep,等待10秒钟。
4.调用API函数VirtualFree,释放之前分配的整型变量的空间。
5.进入死循环,这样应用程序就不会结束。
3.6.2测试方法
1.代码修改完毕后,按F7生成EOS应用程序项目。
2.按F5启动调试,应用程序自动执行后输出的结果可以参照图15-8所示。
3.在应用程序分配虚拟页后,利用10秒后才释放虚拟页的间隙,可以在控制台2中执行命令“vm31”,查看此时应用程序进程的虚拟地址描述符信息;在应用程序释放虚拟页后,可以在控制台2中再次执行命令“vm31”,查看此时应用程序进程的虚拟地址描述符信息。
输出的结果可以参照图15-9所示。
图15-8:
在应用程序进程中分配虚拟页和释放虚拟页
图15-9:
分配虚拟页后和释放虚拟页后,应用程序进程的虚拟地址描述符信息
3.6.3提示
1.API函数VirtualAlloc定义在api/eosapi.c文件的第48行。
此API函数主要调用了EOS内核函数MmAllocateVirtualMemory。
在EOS应用程序中调用函数VirtualAlloc时,除了使用MEM_RESERVE标志外,还必须使用MEM_COMMIT标志。
2.API函数VirtualFree定义在api/eosapi.c文件的第70行。
此API函数主要调用了EOS内核函数MmFreeVirtualMemory。
在EOS应用程序中调用函数VirtualFree时,要使用MEM_RELEASE标志。
3.可以参考本实验文件中的LoopApp.c文件,在应用程序的最后执行一个死循环。
四、思考与练习
1.在本实验3.3中,如果分配了物理页后,没有回收,会对EOS操作系统造成什么样的影响?
目前EOS操作系统内核函数MiAllocateAnyPages能处理所有物理页被分配完毕的情况吗?
例如在没有可分配的物理页的情况下调用该内核函数,是否会返回失败?
如果内核函数MiAllocateAnyPages还不能处理这种极端情况,尝试修改代码解决这个问题。
2.在本实验3.3中,在分配物理页时是调用的内核函数MiAllocateAnyPages,该函数会优先分配空闲页,尝试修改代码,调用内核函数MiAllocateZeroedPages优先分配零页,并调试分配零页的情况。
尝试从性能的角度分析内核函数MiAllocateAnyPages和MiAllocateZeroedPages。
尝试从安全性的角度分析分配零页的必要性。
3.观察本实验3.4中使用“vm”命令输出的系统进程的虚拟地址描述符(图15-3),可以看到在2号描述符和3号描述符之间有两个虚拟页的空隙,尝试结合虚拟页的分配和释放说明产生这个空隙的原因。
4.在系统进程和应用程序进程的逻辑地址空间中,都有一部分空间由虚拟地址描述符来动态管理,尝试从管理方式、位置、大小、用途等方面说明这两部分空间的相同点和不同点。
5.在本实验3.5中,调用MmAllocateVirtualMemory函数分配虚拟页时只使用了MEM_RESERVE标志,没有使用MEM_COMMIT标志,尝试说明这两个标志的区别。
修改代码,在调用MmAllocateVirtualMemory函数时增加使用MEM_COMMIT标志,并调试为虚拟页映射物理页的过程。
6.尝试在启动一个应用程序进程前执行“pm”命令,并记录下此时已经被占用的物理页数量;执行“vm”命令查看系统进程的虚拟地址描述符信息,并记录下系统进程已经分配的虚拟页数量。
启动一个应用程序进程后,再执行“pm”命令,并记录下此时被占用的物理页数量;使用“vm”命令分别查看系统进程和应用程序进程的虚拟地址描述符信息,分别记录下系统进程和应用程序进程已经分配的虚拟页数量。
结合记录的五个数据,尝试说明由于应用程序进程执行而增加的物理页数量与增加的虚拟页数量是否一致。
如果不一致,尝试说明原因。