当前位置:文档之家› Windows虚拟内存管理

Windows虚拟内存管理

Windows虚拟内存管理
Windows虚拟内存管理

基本概念【摘录】

每个进程都被赋予它自己的虚拟地址空间。对于32位进程来说,这个地址空间是4GB,因为32位指针可以拥有从0x000000000至0xFFFFFFFF之间的任何一个值。这使得一个指针能够拥有4 294 967 296个值中的一个值,它覆盖了一个进程的4GB虚拟空间的范围。这是相当大的一个范围。由于每个进程可以接收它自己的私有的地址空间,因此当进程中的一个线程正在运行时,该线程可以访问只属于它的进程的内存。属于所有其他进程的内存则隐藏着,并且不能被正在运行的线程访问。

注意在Windows 2000中,属于操作系统本身的内存也是隐藏的,正在运行的线程无法访问。这意味着线程常常不能访问操作系统的数据。Windows 98中,属于操作系统的内存是不隐藏的,正在运行的线程可以访问。因此,正在运行的线程常常可以访问操作系统的数据,也可以破坏操作系统(从而有可能导致操作系统崩溃)。在Windows 98中,一个进程的线程不可能访问属于另一个进程的内存。

前面说过,每个进程有它自己的私有地址空间。进程A可能有一个存放在它的地址空间中的数据结构,地址是0x12345678,而进程B则有一个完全不同的数据结构存放在它的地址空间中,地址是0x12345678。当进程A中运行的线程访问地址为0x12345678的内存时,这些线程访问的是进程A的数据结构。当进程B中运行的线程访问地址为0x12345678的内存时,这些线程访问的是进程B的数据结构。进程A中运行的线程不能访问进程B的地址空间中的数据结构。反之亦然。

记住,这是个虚拟地址空间,不是物理地址空间。该地址空间只是内存地址的一个范围。在你能够成功地访问数据而不会出现违规访问之前,必须赋予物理存储器,或者将物理存储器映射到各个部分的地址空间。

每个进程的虚拟地址空间都要划分成各个分区。地址空间的分区是根据操作系统的基本实现方法来进行的。不同的Windows内核,其分区也略有不同。

当进程被创建并被赋予它的地址空间时,该可用地址空间的主体是空闲的,即未分配的。若要使用该地址空间的各个部分,必须通过调用VirtualAlloc函数来分配它里边的各个区域。对一个地址空间的区域进行分配的操作称为保留(reserving)。

每当你保留地址空间的一个区域时,系统要确保该区域从一个分配粒度的边界开始。对于不同的CP U平台来说,分配粒度是各不相同的。但是,目前(x86、32位Alpha、64位Alpha和IA-64)都使用64K B这个相同的分配粒度。当你保留地址空间的一个区域时,系统还要确保该区域的大小是系统的页面大小的倍数。页面是系统在管理内存时使用的一个内存单位。与分配粒度一样,不同的CPU,其页面大小也是不同的。x86使用的页面大小是4KB,而Alpha(当既能运行32位Windows 2000也能运行6 4位Windows 2000时)使用的页面大小则是8 KB。

在较老的操作系统中,物理存储器被视为计算机拥有的RAM的容量。换句话说,如果计算机拥有16 MB的RAM,那么加载和运行的应用程序最多可以使用16MB的R A M。今天的操作系统能够使得磁盘空间看上去就像内存一样。磁盘上的文件通常称为页文件,它包含了可供所有进程使用的虚拟内存。

当然,若要使虚拟内存能够运行,需要得到CPU本身的大量帮助。当一个线程试图访问一个字节的内

存时,CPU必须知道这个字节是在RAM中还是在磁盘上。

从应用程序的角度来看,页文件透明地增加了应用程序能够使用的RAM(即内存)的数量。如果计算机拥有64MB的RAM,同时在硬盘上有一个100 MB的页文件,那么运行的应用程序就认为计算机总共拥有164MB的RAM。当然,实际上并不拥有164MB的RAM。相反,操作系统与CPU相协调,共同将R A M的各个部分保存到页文件中,当运行的应用程序需要时,再将页文件的各个部分重新加载到R A M。

由于页文件增加了应用程序可以使用的RAM的容量,因此页文件的使用是视情况而定的。如果没有页文件,那么系统就认为只有较少的RAM可供应用程序使用。但是,我们鼓励用户使用页文件,这样他们就能够运行更多的应用程序,并且这些应用程序能够对更大的数据集进行操作。最好将物理存储器视为存储在磁盘驱动器(通常是硬盘驱动器)上的页文件中的数据。

这样,当一个应用程序通过调用VirtualAlloc函数,将物理存储器提交给地址空间的一个区域时,地址空间实际上是从硬盘上的一个文件中进行分配的。系统的页文件的大小是确定有多少物理存储器可供应用程序使用时应该考虑的最重要的因素,RAM的容量则影响非常小。

现在,当你的进程中的一个线程试图访问进程的地址空间中的一个数据块时,将会发生两种情况之一: 在第一种情况中,线程试图访问的数据是在RAM中。在这种情况下,CPU将数据的虚拟内存地址映射到内存的物理地址中,然后执行需要的访问。

在第二种情况中,线程试图访问的数据不在RAM中,而是存放在页文件中的某个地方。这时,试图访问就称为页面失效,CPU将把试图进行的访问通知操作系统。这时操作系统就寻找RAM中的一个内存空页。如果找不到空页,系统必须释放一个空页。如果一个页面尚未被修改,系统就可以释放该页面。但是,如果系统需要释放一个已经修改的页面,那么它必须首先将该页面从RAM拷贝到页交换文件中,然后系统进入该页文件,找出需要访问的数据块,并将数据加载到空闲的内存页面。然后,操作系统更新它的用于指明数据的虚拟内存地址现在已经映射到RAM中的相应的物理存储器地址中的表。这时CPU重新运行生成初始页面失效的指令,但是这次CPU能够将虚拟内存地址映射到一个物理R A M地址,并访问该数据块。

保护属性

已经分配的物理存储器的各个页面可以被赋予不同的保护属性。x86和Alpha CPU不支持“执行”保护属性,不过操作系统软件却支持这个属性。这些CPU将读访问视为执行访问。这意味着如果将PAGE_EX ECUTE保护属性赋予内存,那么该内存也将拥有读优先权。当然,不应该依赖这个行为特性,因为在其他CPU上的Windows实现代码很可能将“执行”保护视为“仅为执行”保护。

PAGE_NOACCESS 如果试图在该页面上读取、写入或执行代码,就会引发访问违规

PAGE_READONLY 如果试图在该页面上写入或执行代码,就会引发访问违规

PAGE_READWRITE 如果试图在该页面上执行代码,就会引发访问违规

PAGE_EXECUTE 如果试图在该页面上对内存进行读取或写入操作,就会引发访问违规

PAGE_EXECUTE_READ 如果试图在该页面上对内存进行写入操作,就会引发访问违规

PAGE_EXECUTE_READWRITE 对于该页面不管执行什么操作,都不会引发访问违规

PAGE_WRITECOPY 如果试图在该页面上执行代码,就会引发访问违规。如果试图在该页面上写入内存,就会导致系统将它自己的私有页面(受页文件的支持)拷贝赋予该进程

PAGE_EXECUTE_WRITECOPY 对于该地址空间的区域,不管执行什么操作,都不会引发访问违规。如果试图在该页面上的内存中进行写入操作,就会将它自己的私有页面(受页文件的支持)拷贝赋予该进程

几个API函数

通过调用VirtualAlloc函数,可以在进程的地址空间中保留一个区域:

PVOID VirtualAlloc(

PVOID pvAddress,

SIZE_T dwsize,

DWORD fdwAllocationtype,

DWORD fdwProtect);

第一个参数pvAddress包含一个内存地址,用于设定想让系统将地址空间保留在什么地方。在大多数情况下,你为该参数传递NULL。它告诉VirtualAlloc,保存着一个空闲地址区域的记录的系统应该将区域保留在它认为合适的任何地方。系统可以从进程的地址空间的任何位置来保留一个区域,因为不能保证系统可以从地址空间的底部向上或者从上面向底部来分配各个区域。可以使用MEM_TOP_DOWN标志来说明该分配方式。

对大多数程序员来说,能够选择一个特定的内存地址,并在该地址保留一个区域,这是个非同寻常的想法。当你在过去分配内存时,操作系统只是寻找一个其大小足以满足需要的内存块,并分配该内存块,然后返回它的地址。但是,由于每个进程有它自己的地址空间,因此可以设定一个基本内存地址,在这个地址上让操作系统保留地址空间区域。例如,你想将一个从50MB开始的区域保留在进程的地址空间中。这时可以传递52 428 800(50×1024×1024)作为pvAddress参数。如果该内存地址有一个足够大的空闲区域满足你的要求,那么系统就保留这个区域并返回。如果在特定的地址上不存在空闲区域,或者如果空闲区域不够大,那么系统就不能满足你的要求,VirtualAlloc函数返回NULL。注意,为pvAddress参数传递

的任何地址必须始终位于进程的用户方式分区中,否则对VirtualAlloc函数的调用就会失败,导致它返回N ULL.

如果VirtualAlloc函数能够满足你的要求,那么它就返回一个值,指明保留区域的基地址。如果传递一个特定的地址作为pvAddress参数,那么该返回值与传递给VirtualAlloc的值相同,并被圆整为(如果需要的话)64KB边界值。

第二个参数是dwSize,用于设定想保留的区域的大小(以字节为计量单位)。由于系统保留的区域始终必须是CPU页面大小的倍数,因此,如果试图保留一个跨越62KB的区域,结果就会在使用4 KB、8 KB或16 KB页面的计算机上产生一个跨越6 4 K B的区域。

第三个参数是fdwAllocationType,它能够告诉系统你想保留一个区域还是提交物理存储器.若要保留一个地址空间区域,必须传递MEM_RESERV E标识符作为参数的值。

如果保留的区域预计在很长时间内不会被释放,那么可以在尽可能高的内存地址上保留该区域。这样,该区域就不会从进程地址空间的中间位置上进行保留。因为在这个位置上它可能导致区域分成碎片。如果想让系统在最高内存地址上保留一个区域,必须为pvAddress参数和fdwAllocationType参数传递N U L L,还必须逐位使用OR将MEM_TOP_DOWN标志和MEM_RESERVE标志连接起来。

注意在Windows 98下,MEM_TOP_DOWN标志将被忽略。

最后一个参数是fdwProtect,用于指明应该赋予该地址空间区域的保护属性。与该区域相关联的保护属性对映射到该区域的已提交内存没有影响。无论赋予区域的保护属性是什么,如果没有提交任何物理存储器,那么访问该范围中的内存地址的任何企图都将导致该线程引发一个访问违规。当保留一个区域时,应该为该区域赋予一个已提交内存最常用的保护属性。例如,如果打算提交的物理存储器的保护属性是PAG E_ READWRITE(这是最常用的保护属性),那么应该用PAGE_READWRITE保护属性来保留该区域。当区域的保护属性与已提交内存的保护属性相

匹配时,系统保存的内部记录的运行效率最高。

可以使用下列保护属性中的任何一个:PAGE_NOACCESS、PAGE_READWRITE、PAGE_READONL Y、PAGE_EXECUTE、PAGE_EXECUTE_READ或PAGE_EXE CUTE_READWRITE。但是,既不能设定PAGE_WRITECOPY属性,也不能设定PAGE_EXECUTE_WRITECOPY属性。如果设定了这些属性,函数将不保留该区域,并且返回NULL。另外,当保留地址空间区域时,不能使用保护属性标志PAGE_GUA RD,PAGE_NOCACHE或PAGE_WRITECOMBINE,这些标志只能用于已提交的内存。

在保留区域中的提交存储器

当保留一个区域后,必须将物理存储器提交给该区域,然后才能访问该区域中包含的内存地址。系统从它的页文件中将已提交的物理存储器分配给一个区域。物理存储器总是按页面边界和页面大小的块来提交的。

若要提交物理存储器,必须再次调用VirtualAlloc函数。不过这次为fdwAllocationType参数传递的是M EM_COMMIT标志,而不是MEM_RESERV E标志。传递的页面保护属性通常与调用VirtualAlloc来保留区域时使用的保护属性相同(大多数情况下是PAGE_READWRITE),不过也可以设定一个不同的保护属性。

在已保留的区域中,你必须告诉VirtualAlloc函数,你想将物理存储器提交到何处,以及要提交多少物理存储器。为了做到这一点,可以在pvAddress参数中设定你需要的内存地址,并在dwSize参数中设定物理存储器的数量(以字节为计量单位)。注意,不必立即将物理存储器提交给整个区域。

下面让我们来看一个如何提交物理存储器。比如说,你的应用程序是在x86 CPU上运行的,该应用程序保留了一个从地址5 242 880开始的512 KB的区域。你想让应用程序将物理存储器提交给已保留区域的6 KB部分,从2 KB的地方开始,直到已保留区域的地址空间。为此,可以调用带有MEM_COMMIT 标志的VirtualAlloc函数

有时你可能想要在保留区域的同时,将物理存储器提交给它。只需要一次调用VirtualAlloc函数就能进行这样的操作,如下所示:

VirtualAlloc(NIL,SizeOf(ArrayType),

MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);

当系统处理这个函数调用时,它首先要搜索你的进程的地址空间,找出未保留的地址空间中一个地址连续的区域,它必须足够大,原因是已将pvAddress参数设定为NULL。如果为pvAddress设定了内存地址,系统就要查看在该内存地址上是否存在足够大的未保留地址空间。如果系统找不到足够大的未保留地址空间,VirtualAlloc将返回NULL,如果能够保留一个合适的区域,系统就将物理存储器提交给整个区域。无论是该区域还是提交的内存,都将被赋予PAGE_READWRITE保护属性。

最后需要说明的是,VirtualAlloc将返回保留区域和提交区域的虚拟地址,然后该虚拟地址被保存在p vMem变量中。如果系统无法找到足够大的地址空间,或者不能提交该物理存储器,VirtualAlloc将返回N ULL。当用这种方式来保留一个区域和提交物理存储器时,将特定的地址作为pvAddress参数传递给Virtu alAlloc当然是可能的。否则就必须用OR将MEM_TOP_DOWN标志与fdwAllocationType参数连接起来,并为pvAddress参数传递NULL,让系统在进程的地址空间的顶部选定一个适当的区域。

回收虚拟内存和释放地址空间区域

若要回收映射到一个区域的物理存储器,或者释放这个地址空间区域,可调用

BOOL VirtualFree(

LPVOID lpAddress, // address of region of committed pages

DWORD dwSize, // size of region

DWORD dwFreeType // type of free operation

);

当你的进程不再访问区域中的物理存储器时,就可以释放整个保留的区域和所有提交给该区域的物理存储

器,方法是一次调用VirtualFree函数。就这个函数的调用来说,lpAddress参数必须是该区域的基地址。此地址与该区域被保留时VirtualFree函数返回的地址相同。系统知道在特定内存地址上的该区域的大小,因此可以为dwSize参数传递0。实际上,必须为dwSize参数传递0,否则对VirtualFree的调用就会失败。对于第三个参数fdwFreeType,必须传递MEM_RELEASE,以告诉系统将所有映射的物理存储器提交给该区域并释放该区域。当释放一个区域时,必须释放该区域保留的所有地址空间。例如不能保留一个128 K B的区域,然后决定只释放它的64 KB。必须释放所有的128 KB。

当想要从一个区域回收某些物理存储器,但是却不释放该区域时,也可以调用VirtualFree函数,若要回收某些物理存储器,必须在VirtualFree函数的pvAddress参数中传递用于标识要回收的第一个页面的内存地址,还必须在dwSize参数中设定要释放的字节数,并在dwFreeType 参数中传递MEM_DECOMMIT标志。

与提交物理存储器的情况一样,回收时也必须按照页面的分配粒度来进行。这就是说,设定页面中间的一个内存地址就可以回收整个页面。当然,如果pvAddress + dwSize的值位于一个页面的中间,那么包含该地址的整个页面将被回收。因此位于pvAddress 至pvAddress +dwSize范围内的所有页面均被回收。如果dwSize是0,lpAddress是已分配区域的基地址,那么VirtualFree将回收全部范围内的已分配页面。当物理存储器的页面已经回收之后,已释放的物理存储器就可以供系统中的所有其他进程使用,如果试图访问未回收的内存,将会造成访问违规。

改变内存页面的保护属性

可以调用

BOOL VirtualProtect(

LPVOID lpAddress, // address of region of committed pages

DWORD dwSize, // size of the region

DWORD flNewProtect, // desired access protection

PDWORD lpflOldProtect // address of variable to get old protection

);

这里的lpAddress参数指向内存的基地址(它必须位于进程的用户方式分区中),dwSize参数用于指明你想要改变保护属性的字节数,而flNewProtect参数则代表PAGE_*保护属性标志中的任何一个标志,但PA GE_WRITECOPY和PAGE_EXECUTE_WRITECOPY这两个标志除外。最后一个参数lpflOldProtect用来接收原先的保护属性,尽管许多应用程序并不需要该信息,但是必须为该参数传递一个有效地址,否则该函数的运行将会失败。当然,保护属性是与内存的整个页面相关联的,而不是赋予内存的各个字节的。

确定地址空间的状态

用函数称

DWORD V irtualQuery(

LPCVOID lpAddress, // address of region

PMEMORY_BASIC_INFORMATION lpBuffer, // address of information buffer

DWORD dwLength // size of buffer

);

lpAddress参数必须包含你想要查询其信息的虚拟内存地址。lpBuffer参数是你必须分配的PMEMORY_ BASIC_INFORMATION结构的地址,最后一个参数用与制定结构的大小。关于MEMORY_BASIC_INFOR MATION 结构,请参考MSDN帮助或其他资料。

说明,上述介绍的函数都是针对本进程而言的,如果要操作其他进程的内存信息,可以使用*****Ex 结构的函数,例如要查询其他进程的地址空间状态,可以使用VirtualQueryEx函数,用法几乎一样,就是多了一个要查询进程的句柄。

DELPHI中的内存分配

如果你使用DELPHI开发了一些程序,你经常用来分配内存的函数我想大概是,new,GetMem(),AllocMe m()等,他们是怎么实现的呢?观察DELPHI的System.pas以及GetMem.inc源码,你会得到一些启发,注,在Getmem.inc中,Borlnd实现了自己的缺省内存管理器,DELPHI的内存管理器还包括ShareMem.pas以及相应的内存管理模块borlndmm.dll,看到这个名字,如果你用DELPHI做过DLL一定很熟悉吧。至于D ELPHI内存管理器的具体实现,这不是我今天要描述的重点,但有了上面那些API函数以及WINDOWS

分配内存的概念,无论是你写一个内存管理器还是看现有的代码,都已经算是入门了,至于最终如何实现,那需要的将不再是简单的编码知识,而是一种思路。

一个例子:

程序界面:

程序的演示使用:

上面的程序是我写的一个用来演示WINDOWS虚拟内存概念的例子。

1、首先我们可以用他来了解一下windows进程地址空间如何分区的情况。启动程序后,在【从进程虚拟内存开始地址显示××个页面信息】的EDIT中输入20,然后点击【显示】按钮,在我的机器上(根据CPU 以及WINDOWS内核的不同,在你机器上会有不同),你会发现第17个页面是红色(程序中代表已经提交的页面),而前16个是黄色,代表FREE的区域,从程序右边的显示信息你还可以看到他们的具体情况,计算以下,前16个,刚好是64K,和本文最开始的那个【进程地址空间分区图】对比以下,你会有更多的

了解。

注意:在测试中,我输入了显示20个页面的信息,你当然可以用其他的数字,但因为在做这个示例程序时,过于匆忙,我只画了20个标尺信息,在我演示的信息中,20已经足够反映一些事情。另外,因为WIN32虚拟地址空间是4G,所以如果你将我程序中用来显示进程空间划分情况的代码稍加改动,就可以做到对整个4G的历遍,而我的程序中用来循环历遍地址空间信息的代码中用的是longint类型,他不足以支持4G。程序执行情况如上图所示。

2、对windows中保留、提交、释放等概念加深了解。运行程序,点击【申请内存-保留】按钮,程序将在自己的进程空间中保留20个页面大小的空间,然后提交1个页面、4、5页面等,请仔细观察下面的图表信息以及右方的列表信息。然后,你还可以进行下面【高级】信息框中的一些操作,自己定义要从那里提交多大的空间,例如,你首先点击【申请内存-保留】按钮,然后在起始地址偏移中输入1,大小中输入1,你可以看到,虽然你只要求1个BYTE的空间,但依然会为你分配一个页面。

3、对页面保护属性加深了解。通常而言我们在编写代码的时候,经常会出现“×××××内存访问错误”信息,在这个示例程序中,你可以做一些这方面的测试。在【尝试对第一个页面进行写操作】按钮中,我对分配空间进行了写操作。我定义了一个这样的结构,

TTestMemAlloc=record

Data : array[0..4093] of Char;

注意4093这个信息,在我的机器上,一个页面大小是4096 Byte,这里定义4093代表一个页面就足够了。var

arrayTemp : ^TTestMemAlloc;

begin

arrayTemp := Arrayptr;//将分配空间的地址传递给指向TTestMemAlloc类型的指针

arrayTemp^.Data := 'wuiasdfasdfasdfasdfasf';//此时的读写实际上是对Arrayptr的读写

showmessage(pchar(Arrayptr));//如果写入成功,从Arrayptr中读取信息

例如,你首先通过【申请内存-保留】按钮保留一块区域,然后提交页面1,因为对页面1,我代码中设置的保护属性是PAGE_READONLY,所以在此时,你尝试进行写操作是会失败的。你可以通过【修改保护属性】按钮来将页面1的保护属性修改为PAGE_READWRITE,再尝试写操作,OK! 你还可以换一个方式来测试,将代码中的Data : array[0..4093] of Char;改为4099,总之,是大于一个页面,此时,你依然只对页面1进行内存提交,并赋值可以读写的属性,你会发现,当你尝试进行写入操作时,依然会失败,原因很简单,TTestMemAlloc结构的大小已经大于一个页面,而第二个页面,我们并没有提交。

程序源码:

...{ }

unit AllowMemun;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, ExtCtrls, Buttons;

//常量定义,用来表示程序要一共要分配多少个页面

const

MAXUSEPAGE=20;

type

// 用来尝试对分配的内存进行写操作的结构

TTestMemAlloc=record

Data : array[0..4093] of Char;

end;

TfrmAllowMem = class(TForm)

GroupBox1: TGroupBox;

Image1: TImage;

Image2: TImage;

btnPost1: TButton;

Button5: TButton;

btnPost45: TButton;

btnPostLast: TButton;

GroupBox2: TGroupBox;

btnReserve: TButton;

btnFree: TButton;

lbpgSize: TLabel;

Label1: TLabel;

edOffSize: TEdit;

edSize: TEdit;

cmbxP: TComboBox;

btnPost: TButton;

btnDeCom: TButton;

btChangeP: TButton;

lsbxInfo: TListBox;

panel1: TPanel;

btnShow: TButton;

edCount: TEdit;

Label2: TLabel;

Button1: TButton;

procedure btnReserveClick(Sender: TObject); procedure btnFreeClick(Sender: TObject);

procedure btnPost1Click(Sender: TObject);

procedure Button5Click(Sender: TObject);

procedure btnPost45Click(Sender: TObject); procedure FormCreate(Sender: TObject);

procedure btnPostLastClick(Sender: TObject); procedure btnPostClick(Sender: TObject);

procedure btnDeComClick(Sender: TObject); procedure btChangePClick(Sender: TObject); procedure btnShowClick(Sender: TObject);

procedure Button1Click(Sender: TObject);

private

Arrayptr : Pointer;

PageSize : integer;

function GetPageSize:DWORD;

procedure showMemBackupMap;

procedure ShowMemMap(StartAddress : Pointer;ShowPageCount : integer); public

...{ Public declarations }

end;

var

frmAllowMem: TfrmAllowMem;

implementation

uses RTLConsts, Types;

...{$R *.dfm}

function DisplayProtections(ProtectFlag: DWORD):string;

begin

case ProtectFlag of

PAGE_READONLY: result:='PAGE_READONLY';

PAGE_READWRITE: result:='P AGE_READWRITE';

PAGE_WRITECOPY: result:='PAGE_WRITECOPY';

PAGE_EXECUTE: result:='P AGE_EXECUTE';

PAGE_EXECUTE_READ: result:='P AGE_EXECUTE_READ';

PAGE_EXECUTE_WRITECOPY: result:='PAGE_EXECUTE_WRITECOPY'; PAGE_GUARD: result:='P AGE_GAURD';

PAGE_NOACCESS: result:='PAGE_NOACCESS';

PAGE_NOCACHE: result:='PAGE_NOCACHE';

end;

end;

function TfrmAllowMem.GetPageSize:DWORD ;

var

si : SYSTEM_INFO;

begin

GetSystemInfo(si);

Result := SI.dwPageSize;

end;

procedure TfrmAllowMem.btnReserveClick(Sender: TObject);

begin

Arrayptr := V irtualAlloc(NIL,PageSize * MAXUSEPAGE,

MEM_RESERVE, PAGE_READWRITE);

if Arrayptr = nil then

begin

ShowMessage('分配内存失败');

Exit;

end;

ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

begin

V irtualFree(Arrayptr,PageSize,MEM_DECOMMIT);

ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

procedure TfrmAllowMem.btnFreeClick(Sender: TObject);

begin

V irtualFree(Arrayptr, 0, MEM_RELEASE) ;

ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

procedure TfrmAllowMem.btnPost1Click(Sender: TObject);

var

p : Pointer;

begin

p := V irtualAlloc(Arrayptr,PageSize,MEM_COMMIT, PAGE_READONLY);

if p= nil then showmessage('分配失败');

ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

procedure TfrmAllowMem.btnPost45Click(Sender: TObject);

var

p : Pointer;

begin

p := V irtualAlloc(pointer(longint(Arrayptr)+PageSize*3),PageSize*2,MEM_COMMIT,P AGE_READWRITE); if p = nil then ShowMessage('分配失败');

ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

procedure TfrmAllowMem.btnPostLastClick(Sender: TObject);

var

p : Pointer;

begin

p := V irtualAlloc(pointer(longint(Arrayptr)+PageSize*(MAXUSEPAGE-1)),PageSize,MEM_COMMIT,PAGE _READONLY);

if p = nil then ShowMessage('分配失败');

ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

procedure TfrmAllowMem.FormCreate(Sender: TObject);

begin

lbpgSize.Caption := IntToStr(GetPageSize)+'Byte';

PageSize := GetPageSize;

showMemBackupMap;

end;

procedure TfrmAllowMem.btnPostClick(Sender: TObject);

var

p : Pointer;

PageP : DWORD;

begin

PageP := PAGE_READONLY;

case cmbxP.ItemIndex of

0 : PageP := PAGE_NOACCESS;

1 : PageP := PAGE_READONLY;

2 : PageP := PAGE_READWRITE;

p := V irtualAlloc(pointer(longint(Arrayptr)+StrToInt(edOffSize.Text)),

StrToInt(edSize.Text),

MEM_COMMIT,

PageP);

if p= nil then

showmessage('分配失败')

else ShowMemMap(Arrayptr,MAXUSEPAGE); end;

procedure TfrmAllowMem.btnDeComClick(Sender: TObject);

begin

V irtualFree(pointer(longint(Arrayptr)+StrToInt(edOffSize.Text)) ,

StrToInt(edSize.Text),

MEM_DECOMMIT);

ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

procedure TfrmAllowMem.btChangePClick(Sender: TObject);

var

PageP : DWORD;

OldProt : integer;

begin

PageP := PAGE_READONLY;

case cmbxP.ItemIndex of

0 : PageP := PAGE_NOACCESS;

1 : PageP := PAGE_READONLY;

2 : PageP := PAGE_READWRITE;

end;

if not V irtualProtect(pointer(longint(Arrayptr)+StrToInt(edOffSize.Text)) , StrToInt(edSize.Text),

@OldProt)

then ShowMessage('修改保护属性出错!')

else ShowMemMap(Arrayptr,MAXUSEPAGE);

end;

procedure TfrmAllowMem.showMemBackupMap;

var

wd,i,bwd : integer;

begin

Image2.Picture := nil;

wd := Image2.Width div MAXUSEPAGE;

bwd := wd div 2;

Image2.Canvas.Brush.Color := clWhite;

Image2.Canvas.FillRect(Image2.ClientRect);

for i := 1 to MAXUSEPAGE-1 do

begin

Image2.Canvas.MoveTo(wd*i,0);

Image2.Canvas.LineTo(wd*i,Image2.Height);

Image2.Canvas.TextOut((i-1)*wd+bwd,Image2.Height div 2,IntToStr(i));

end;

end;

procedure TfrmAllowMem.ShowMemMap(StartAddress : Pointer;ShowPageCount : integer); var

MemInfo: TMemoryBasicInformation;

PageCount,UseCount,wd : integer;

cl : TColor;

Addr : Pointer;

Addr := StartAddress;

UseCount := 0;

Image1.Picture := nil;

Image1.Canvas.Rectangle(Image1.ClientRect) ;

lsbxInfo.Clear;

wd := Image1.Width div ShowPageCount;

while Longint(Addr) < Longint(Arrayptr)+ShowPageCount*PageSize do

begin

V irtualQuery(addr, MemInfo, SizeOf(TMemoryBasicInformation));

with lsbxInfo do

begin

Items.Add('-----------------------------');

Items.Add('基地址: '+IntToHex(Longint(MemInfo.BaseAddress),8));

Items.Add('分配地址: '+IntToHex(Longint(MemInfo.AllocationBase),8));

Items.Add('区域大小: '+IntToStr(MemInfo.RegionSize)+' bytes'+'['+

IntToHex(MemInfo.RegionSize,8 )+']');

PageCount := MemInfo.RegionSize div PageSize;

Items.Add('所分配保护属性: '+DisplayProtections(MemInfo.AllocationProtect)); Items.Add('访问的保护属性: '+DisplayProtections(MemInfo.Protect));

cl := clWhite;

case MemInfo.State of

MEM_COMMIT: begin

cl := clRed;

Items.Add('内存状态: MEM_COMMIT');

end;

MEM_FREE: begin

Items.Add('内存状态: MEM_FREE');

end;

MEM_RESERVE: begin

Items.Add('内存状态: MEM_RESERVE');

cl := clGreen;

end;

end;

case MemInfo.Type_9 of

MEM_IMAGE: Items.Add('内存类型: MEM_IMAGE');

MEM_MAPPED: Items.Add('内存类型: MEM_MAPPED');

MEM_PRIVATE: Items.Add('内存类型: MEM_PRIVATE');

end;

end;

Image1.Canvas.Rectangle(Rect(

UseCount*wd,

0,

(UseCount+PageCount)*wd,

Image1.Height));

Image1.Canvas.Brush.Color := cl;

Image1.Canvas.FillRect(Rect(

UseCount*wd,

0,

(UseCount+PageCount)*wd,

Image1.Height));

UseCount := UseCount + PageCount;

Addr := Pointer(Longint(MemInfo.BaseAddress)+MemInfo.RegionSize); end;

北理工操作系统内存管理实验报告

实验三:内存管理 班级: 学号:

姓名: 一、实验目的 1.通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解; 2.熟悉虚存管理的页面淘汰算法; 3.通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。 二、实验要求 1.设计一个请求页式存储管理方案(自己指定页面大小),并予以程序实现。 并产生一个需要访问的指令地址流。它是一系列需要访问的指令的地址。为不失一般性,你可以适当地(用人工指定地方法或用随机数产生器)生成这个序列。 2.页面淘汰算法采用FIFO页面淘汰算法,并且在淘汰一页时,只将该页在页 表中抹去。而不再判断它是否被改写过,也不将它写回到辅存。 3.系统运行既可以在Windows,也可以在Linux。 三、实验流程图

图1 页式存储管理程序参考流程 四、实验环境 硬件设备:个人计算机。 系统软件:windows操作系统,Visual C++6.0编译环境。 五、实验结果

说明:模拟产生35个指令地址,随机产生20个指令地址进行排队,假设主存中共有10个工作集页帧。将前9个指令调入内存,因为前9个指令中,页号为13的指令有两个,所以调入内存中共有8页。此时主存中还有两个空闲帧。此时按刚才随机顺序进行访问指令工作。前9页因都在主存中可直接调用。第10个随机地址为页号为5的指令,也在主存中,也可直接调用。页号为24,3因不在主存中,需要调用进主存。此时主存已满。然后主存需要进行调用页号为27号的指令,因主存已满,需要执行FIFO算法,将最先进入主存的页号为30的指令调出,将27号放入第1000000帧。以后需要调用的页面按照存在就无需调用,否则按FIFO原则进行调页工作。 六、实验感想 七、实验代码 #include

实验三:存储管理

实验三:存储管理 IMB standardization office【IMB 5AB- IMBK 08- IMB 2C】

一、实验名称 实验三:存储管理 [1]Windows Server 2003内存结构 [2] Windows Server 2003虚拟内存 二、 [1]实验目的 1)通过实验了解windows Server 2003内存的使用,学习如何在应用程序中管理内存、体会Windows应用程序内存的简单性和自我防护能力。 2)了解windows Server 2003的内存结构和虚拟内存的管理,进而了解进程堆和windows为使用内存而提供的一些扩展功能。 三、 [1]实验内容 四、 [1]实验步骤 Windows提供了一个API即GetSystemInfo() ,以便用户能检查系统中虚拟内存的一些特性。程序5-1显示了如何调用该函数以及显示系统中当前内存的参数。 步骤1:登录进入Windows Server 2003 。 步骤2:在“开始”菜单中单击“程序”-“Microsoft Visual Studio 6.0”–“Microsoft Visual C++ 6.0”命令,进入Visual C++窗口。 步骤3:在工具栏单击“打开”按钮,在“打开”对话框中找到并打开实验源程序。 程序5-1:获取有关系统的内存设置的信息 步骤4:单击“Build”菜单中的“Compile ”命令,并单击“是”按钮确认。系统对进行编译。 步骤5:编译完成后,单击“Build”菜单中的“Build ”命令,建立可执行文件。 操作能否正常进行如果不行,则可能的原因是什么 答:操作能正常进行。 _____________________________________________________ 步骤6:在工具栏单击“Execute Program” (执行程序) 按钮,执行程序。 运行结果 (分行书写。如果运行不成功,则可能的原因是什么?) : 1) 虚拟内存每页容量为: 2) 最小应用地址: 0x00010000 3) 最大应用地址为: 0x7ffeffff 4) 当前可供应用程序使用的内存空间为: 5) 当前计算机的实际内存大小为: 阅读和分析程序5-1,请回答问题:

Windows虚拟内存不足解决方法

Windows虚拟内存不足解决方法 全大中https://www.doczj.com/doc/1e14082935.html, | 2006-04-26 09:03 | 引:经常听别人说起虚拟内存,请问什么是虚拟内存?为什么我的电脑在使用过一段时间后,总是提示虚拟内存太低,是不是只有重新安装操作系统才能解决问题? ??? 问:经常听别人说起虚拟内存,请问什么是虚拟内存?为什么我的电脑在使用过一段时间后,总是提示虚拟内存太低,是不是只有重新安装操作系统才能解决问题? 答:Windows操作系统用虚拟内存来动态管理运行时的交换文件。为了提供比实际物理内存还多的内存容量以供使用,Windows操作系统占用了硬盘上的一部分空间作为虚拟内存。当CPU有需 ? 求时,首先会读取内存中的资料。当所运行的程序容量超过内存容量时,Windows 操作系统会将需要暂时储存的数据写入硬盘。所以,计算机的内存大小等于实际物理内存容量加上“分页文件”(就是交换文件)的大小。如果需要的话,“分页文件”会动用硬盘上所有可以使用的空间。 如果你的系统虚拟内存太低,可以鼠标右击“我的电脑”选择“属性→高级→性能下设置→高级→打开虚拟内存设置”,可以重新设置最大值和最小值,按物理内存的1.5~2倍来添加数值,也可以更改虚拟内存的存放位置,可以设置放到其他容量较大的硬盘分区,让系统虚拟内存有充分的空间,让系统运行更快。 虚拟内存太低有三种解决办法: 1. 自定义的虚拟内容的容量(系统默认是自动)太小,可以重新划分大小。 2. 系统所在的盘(一般是C盘)空余的容量太小而运行的程序却很大,并且虚拟内存通常被默认创建在系统盘目录下,我们通常可以删除一些不用的程序,并把文档图片以及下载的资料等有用文件移动到其他盘中,并清理“回收站”,使系统盘保持1GB以上的空间,或者将虚拟内存定义到其他空余空间多的盘符下。 3. 系统盘空余的容量并不小,但因为经常安装、下载软件,并反复删除造成文件碎片太多,也是容易造成虚拟内存不足的原因之一,虚拟内存需要一片连续的空间,尽管磁盘空余容量大,但没有连续的空间,也无法建立虚拟内存区。可以用磁盘工具整理碎片。 Windows虚拟内存不足的几种解决方法问: 经常听别人说起虚拟内存,请问什么是虚拟内存?为什么我的电脑在使用过一段时间后,总是提示虚拟内存太低,是不是只有重新安装操作系统才能解决问题? 答:Windows操作系统用虚拟内存来动态管理运行时的交换文件。为了提供比实际物理内存还多的内存容量以供使用,Windows操作系统占用了硬盘上的一部分

实验三存储管理实验

实验三存储管理实验 Pleasure Group Office【T985AB-B866SYT-B182C-BS682T-STT18】

实验三存储管理实验 一. 目的要求: 1、通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解。熟悉虚存管理的各种页面淘汰算法。 2、通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。二.实验内容: 1、设计一个固定式分区分配的存储管理方案,并模拟实现分区的分配和回收过程。 可以假定每个作业都是批处理作业,并且不允许动态申请内存。为实现分区的分配和回收,可以设定一个分区说明表,按照表中的有关信息进行分配,并根据分区的分配和回收情况修改该表。 算法描述: 本算法将内存的用户区分成大小相等的四个的分区,设一张分区说明表用来记录分区,其中分区的表项有分区的大小、起始地址和分区的状态,当系统为某个作业分配主存空间时,根据所需要的内存容量,在分区表中找到一个足够大的空闲分区分配给它,然后将此作业装入内存。如果找不到足够大的空闲分区,则这个作业暂时无法分配内存空间,系统将调度另一个作业。当一个作业运行结束时,系统将回收改作业所占据的分区并将该分区改为空闲。 算法原程序 #include "" #include "" #include <>

#include <> #define PCB_NUM 5 行程序."); printf("\n\t\t\t0.退出程序."); scanf("%d",&m); switch(m) { case1: break; case0: system("cls"); menu(); break; default: system("cls"); break; } } void paixu(struct MemInf* ComMem,int n) { int i,j,t; for(j=0; jComMem[i+1].size) { t=ComMem[i].size; ComMem[i].size=ComMem[i+1].size; ComMem[i+1].size=t; } } void paixu2() { int i,j,t; for(j=0; j<4; j++) for(i=0; i<4-j; i++) if(pcbList[i].size>pcbList[i+1].size) { t=pcbList[i].size; pcbList[i].size=pcbList[i+1].size; pcbList[i+1].size=t; } } void main() { DD: menu();

操作系统实验之内存管理实验报告

学生学号 实验课成绩 武汉理工大学 学生实验报告书 实验课程名称 计算机操作系统 开 课 学 院 计算机科学与技术学院 指导老师姓名 学 生 姓 名 学生专业班级 2016 — 2017 学年第一学期

实验三 内存管理 一、设计目的、功能与要求 1、实验目的 掌握内存管理的相关内容,对内存的分配和回收有深入的理解。 2、实现功能 模拟实现内存管理机制 3、具体要求 任选一种计算机高级语言编程实现 选择一种内存管理方案:动态分区式、请求页式、段式、段页式等 能够输入给定的内存大小,进程的个数,每个进程所需内存空间的大小等 能够选择分配、回收操作 内购显示进程在内存的储存地址、大小等 显示每次完成内存分配或回收后内存空间的使用情况 二、问题描述 所谓分区,是把内存分为一些大小相等或不等的分区,除操作系统占用一个分区外,其余分区用来存放进程的程序和数据。本次实验中才用动态分区法,也就是在作业的处理过程中划分内存的区域,根据需要确定大小。 动态分区的分配算法:首先从可用表/自由链中找到一个足以容纳该作业的可用空白区,如果这个空白区比需求大,则将它分为两个部分,一部分成为已分配区,剩下部分仍为空白区。最后修改可用表或自由链,并回送一个所分配区的序号或该分区的起始地址。 最先适应法:按分区的起始地址的递增次序,从头查找,找到符合要求的第一个分区。

最佳适应法:按照分区大小的递增次序,查找,找到符合要求的第一个分区。 最坏适应法:按分区大小的递减次序,从头查找,找到符合要求的第一个分区。 三、数据结构及功能设计 1、数据结构 定义空闲分区结构体,用来保存内存中空闲分区的情况。其中size属性表示空闲分区的大小,start_addr表示空闲分区首地址,next指针指向下一个空闲分区。 //空闲分区 typedef struct Free_Block { int size; int start_addr; struct Free_Block *next; } Free_Block; Free_Block *free_block; 定义已分配的内存空间的结构体,用来保存已经被进程占用了内存空间的情况。其中pid作为该被分配分区的编号,用于在释放该内存空间时便于查找。size表示分区的大小,start_addr表示分区的起始地址,process_name存放进程名称,next指针指向下一个分区。 //已分配分区的结构体 typedef struct Allocate_Block { int pid; int size; int start_addr; char process_name[PROCESS_NAME_LEN]; struct Allocate_Block *next; } Allocate_Block; 2、模块说明 2.1 初始化模块 对内存空间进行初始化,初始情况内存空间为空,但是要设置内存的最大容量,该内存空间的首地址,以便之后新建进程的过程中使用。当空闲分区初始化

实验三动态分区存储管理方式的主

实验三动态分区存储管理方式的主存分配回收 一、实验目的 深入了解动态分区存储管理方式主存分配回收的实现。 二、实验预备知识 存储管理中动态分区的管理方式。 三、实验内容 编写程序完成动态分区存储管理方式的主存分配回收的实现。实验具体包括: 首先确定主存空间分配表;然后采用最优适应算法完成主存空间的分配和回收;最后编写主函数对所做工作进行测试。 四、提示与讲解 动态分区管理方式预先不将主存划分成几个区域,而把主存除操作系统占用区域外的空间看作一个大的空闲区。当作业要求装入主存时,根据作业需要主存空间的大小查询主存内各个空闲区,当从主存空间中找到一个大于或等于该作业大小的主存空闲区时,选择其中一个空闲区,按作业需求量划出一个分区装入该作业。作业执行完后,它所占的主存分区被收回,成为一个空闲区。如果该空闲区的相邻分区也是空闲区,则需要将相邻空闲区合并成一个空闲区。 实现动态分区的分配和回收,主要考虑的问题有三个: 第一,设计记录主存使用情况的数据表格,用来记录空闲区和作业占用的区域;第二,在设计的数据表格基础上设计主存分配算法;第三,在设计的数据表格基础上设计主存回收算法。 首先,考虑第一个问题: 设计记录主存使用情况的数据表格,用来记录空闲区和作业占用的区域。 由于动态分区的大小是由作业需求量决定的,故分区的长度是预先不固定的,且分区的个数也随主存分配和回收变动。总之,所有分区情况随时可能发生变化,数据表格的设计必须和这个特点相适应。由于分区长度不同,因此设计的表格应该包括分区在主

存中的起始地址和长度。由于分配时空闲区有时会变成两个分区: 空闲区和已分分区,回收主存分区时,可能会合并空闲分区,这样如果整个主存采用一张表格记录已分分区和空闲区,就会使表格操作繁琐。主存分配时查找空闲区进行分配,然后填写已分配区表,主要操作在空闲区;某个作业执行完后,将该分区变成空闲区,并将其与相邻的空闲区合并,主要操作也在空闲区。 由此可见,主存的分配和回收主要是对空闲区的操作。这样为了便于对主存空间的分配和回收,就建立两张分区表记录主存使用情况,一张表格记录作业占用分区的 “已分配区表”;一张是记录空闲区的“空闲区表”。这两张表的实现方法一般有两种,一种是链表形式,一种是顺序表形式。在实验中,采用顺序表形式,用数组模拟。由于顺序表的长度必须提前固定,所以无论是“已分配区表”还是“空闲区 表”都必须事先确定长度。它们的长度必须是系统可能的最大项数,系统运行过程中才不会出错,因而在多数情况下,无论是“已分配区表”还是“空闲区表”都有空闲栏目。已分配区表中除了分区起始地址、长度外,也至少还要有一项“标志”,如果是空闲栏目,内容为“空”,如果为某个作业占用分区的登记项,内容为该作业的作业名;空闲区表中除了分区起始地址、长度外,也要有一项“标志”,如果是空闲栏目,内容为“空”,如果为某个空闲区的登记项,内容为“未分配”。在实际系统中,这两表格的内容可能还要多,实验中仅仅使用上述必须的数据。为此, “已分配区表”和“空闲区表”在实验中有如下的结构定义。 已分配区表的定义: #define n 10// 假定系统允许的最大作业数量为n struct {float address;// 已分分区起始地址 float length; // 已分分区长度,单位为字节 int flag;// 已分配区表登记栏标志, “0表”示空栏目,实验中只支持一个字符的作业名}used_table[n];// 已分配区表 空闲区表的定义:

操作系统实验五 Windows XP 虚拟内存管理

实验五 Windows XP 虚拟内存管理 一实验目的 1) 了解存储器管理以及虚拟存储器管理的基本原理 2)了解和学习Windows系统管理工具中关于内存管理的设置和使用; 二实验环境 需要准备一台运行Windows XP操作系统的计算机。 三背景知识 虚拟存储器技术是当代计算机中广泛采用的内存管理方案,在Windows XP中合理的进行虚拟内存的设置,可以更有效的提高系统的工作效率。利用系统自带的系统监视器可以查看虚拟内存的使用情况,根据使用情况可以灵活的进行虚拟内存的管理。 四实验内容与步骤 启动并进入Windows环境,单击Ctrl + Alt + Del键,或者右键单击任务栏,在快捷菜单中单击“任务管理器”命令,打开“任务管理器”窗口。 步骤1:当前机器中由你打开,正在运行的应用程序有: 1) 5.doc[兼容模式]-Microsoft Word 2) 常州大学-Windows Internet Explorer 3) 常州大学教务单点登录接入平台- Windows Internet Explorer 步骤2:单击“进程”选项卡,一共显示了 33 个进程。请试着区分一下,其中: 系统 (SYSTEM) 进程有 19 个,填入表2-1中。 表2-1 实验记录 映像名称用户名CPU使用率内存使用进程实现的功能Svchost.exe SYSTEM 00 4416K NT Kernel &System Service.exe SYSTEM 00 3272K Windows会话管理器 Sqlservr.ex e SYSTEM 00 9580K Client Server Runtime Process LMS.exe SYSTEM 00 2912K 服务和控制器应用程序MDM.exe SYSTEM 00 3424K Local Security Authority Process Inetinfo.exe SYSTEM 00 9780K 本地会话管理器服务Spoolsv.exe SYSTEM 00 5612K Windows 服务主进程 Ati2evxx.e xe SYSTEM 00 4024K 360主动防御服务模块 Svchost.exe SYSTEM 00 24912K Windows 登录应用程序Svchost.exe SYSTEM 00 5084K Windows 服务主进程Service.exe SYSTEM 00 3476K 服务和控制器应用程序Isass.exe SYSTEM 00 1736K Local Security Authority Process

存储管理实验报告

实验三、存储管理 一、实验目的: ? 一个好的计算机系统不仅要有一个足够容量的、存取速度高的、稳定可靠的主存储器,而且要能合理地分配和使用这些存储空间。当用户提出申请存储器空间时,存储管理必须根据申请者的要求,按一定的策略分析主存空间的使用情况,找出足够的空闲区域分配给申请者。当作业撤离或主动归还主存资源时,则存储管理要收回作业占用的主存空间或归还部分主存空间。主存的分配和回收的实现虽与主存储器的管理方式有关的,通过本实验理解在不同的存储管理方式下应怎样实现主存空间的分配和回收。 在计算机系统中,为了提高主存利用率,往往把辅助存储器(如磁盘)作为主存储器的扩充,使多道运行的作业的全部逻辑地址空间总和可以超出主存的绝对地址空间。用这种办法扩充的主存储器称为虚拟存储器。通过本实验理解在分页式存储管理中怎样实现虚拟存储器。 在本实验中,通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解。熟悉虚存管理的各种页面淘汰算法通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。 二、实验题目: 设计一个可变式分区分配的存储管理方案。并模拟实现分区的分配和回收过程。 对分区的管理法可以是下面三种算法之一:(任选一种算法实现) 首次适应算法 循环首次适应算法 最佳适应算法 三.实验源程序文件名:cunchuguanli.c

执行文件名:cunchuguanli.exe 四、实验分析: 1)本实验采用可变分区管理,使用首次适应算法实现主存的分配和回收 1、可变分区管理是指在处理作业过程中建立分区,使分区大小正好适合作业的需求,并 且分区个数是可以调整的。当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入,作业等待。随着作业的装入、完成,主存空间被分成许多大大小小的分区,有的分区被作业占用,而有的分区是空闲的。 为了说明那些分区是空闲的,可以用来装入新作业,必须有一张空闲说明表 ? 空闲区说明表格式如下:? 第一栏 第二栏 其中,起址——指出一个空闲区的主存起始地址,长度指出空闲区的大小。 长度——指出从起始地址开始的一个连续空闲的长度。 状态——有两种状态,一种是“未分配”状态,指出对应的由起址指出的某个长度的区域是空闲区;另一种是“空表目”状态,表示表中对应的登记项目是空白(无效),可用来登记新的空闲区(例如,作业完成后,它所占的区域就成了空闲区,应找一个“空表目”栏登记归还区的起址和长度且修改状态)。由于分区的个数不定,所以空闲区说明表中应有适量的状态为“空表目”的登记栏目,否则造成表格“溢出”无法登记。 2、当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的空闲区。 有时找到的空闲区可能大于作业需要量,这时应把原来的空闲区变成两部分:一部分分

Windows虚拟内存管理

基本概念【摘录】 每个进程都被赋予它自己的虚拟地址空间。对于32位进程来说,这个地址空间是4GB,因为32位指针可以拥有从0x000000000至0xFFFFFFFF之间的任何一个值。这使得一个指针能够拥有4 294 967 296个值中的一个值,它覆盖了一个进程的4GB虚拟空间的范围。这是相当大的一个范围。由于每个进程可以接收它自己的私有的地址空间,因此当进程中的一个线程正在运行时,该线程可以访问只属于它的进程的内存。属于所有其他进程的内存则隐藏着,并且不能被正在运行的线程访问。 注意在Windows 2000中,属于操作系统本身的内存也是隐藏的,正在运行的线程无法访问。这意味着线程常常不能访问操作系统的数据。Windows 98中,属于操作系统的内存是不隐藏的,正在运行的线程可以访问。因此,正在运行的线程常常可以访问操作系统的数据,也可以破坏操作系统(从而有可能导致操作系统崩溃)。在Windows 98中,一个进程的线程不可能访问属于另一个进程的内存。 前面说过,每个进程有它自己的私有地址空间。进程A可能有一个存放在它的地址空间中的数据结构,地址是0x12345678,而进程B则有一个完全不同的数据结构存放在它的地址空间中,地址是0x12345678。当进程A中运行的线程访问地址为0x12345678的内存时,这些线程访问的是进程A的数据结构。当进程B中运行的线程访问地址为0x12345678的内存时,这些线程访问的是进程B的数据结构。进程A中运行的线程不能访问进程B的地址空间中的数据结构。反之亦然。 记住,这是个虚拟地址空间,不是物理地址空间。该地址空间只是内存地址的一个范围。在你能够成功地访问数据而不会出现违规访问之前,必须赋予物理存储器,或者将物理存储器映射到各个部分的地址空间。 每个进程的虚拟地址空间都要划分成各个分区。地址空间的分区是根据操作系统的基本实现方法来进行的。不同的Windows内核,其分区也略有不同。

实验3内存管理 空闲分区表

南京信息工程大学实验(实习)报告实验(实习)名称实验3 内存管理日期 14.5.30 得分指导教师 系计软院专业软件工程年级班次姓名学号 实验3 内存管理 1、程序中使用的数据结构及符号说明。 struct form{//空闲分区表单 int startaddress;//起址 int size;//长度 char state;//状态r代表未分配,e表示空表单 }; struct work{//作业表单 int id;//作业号 int size;//申请空间大小 int from;//起址,正在执行的程序的起址,就绪程序为0k,完成程序为-1k char state;//作业状态,r表示就绪,d表示正在运作,o表示作业完成 }; 2、作业流程 【1】创建作业表 【2】创建空闲分区表 【3】为作业4申请空闲分区 【4】回收作业2、3的申请量 【5】打印作业完成情况 【6】回收作业1、4的申请量 【7】打印作业完成情况 3、打印一份源程序并附上注释。 #include #define NUM 10//表单长度 struct form{//空闲分区表单 int startaddress;//起址 int size;//长度 char state;//状态r代表未分配,e表示空表单 }; struct work{//作业表单 int id;//作业号 int size;//申请空间大小 int from;//起址 char state;//作业状态,r表示就绪,d表示正在运作,o表示作业完成 };

void showallwork(work *w){//展示所有作业情况 printf("以下是所有作业情况:\n"); printf("----------------------------------\n"); printf("作业号所需空间大小起始地址状态\n"); printf("----------------------------------\n"); for(int i = 0 ;i < 4;i++) { printf("%4d %8dk %8dk%6c\n",w[i].id ,w[i].size ,w[i].from ,w[i].state ); } printf("----------------------------------\n"); printf("《r表示就绪状态,d表示正在执行,o表示完成》"); printf("\n"); printf("\n"); } void Init_work(work *w){//初始化作业 printf(" 请输入作业号所需空间起始地址(0表示地址未分配): \n"); for(int i =0 ; i<4 ;i++) { printf(" "); scanf("%d%dk%dk",&w[i].id,&w[i].size,&w[i].from); if(w[i].from ) w[i].state = 'd'; else w[i].state = 'r'; printf("------------------------作业《%d》已经创建\n",w[i].id ); } showallwork(w); printf("初始化作业完成\n"); printf("\n"); printf("\n"); } void Init_forms(form *f){//初始化表单 printf("请输入起址长度:\n"); for(int i=0,j=1;i

操作系统实验内存分配

精心整理西安邮电大学 (计算机学院) 课内实验报告 1. (1 (2 (3 原因,写出实验报告。 2.实验要求: 1)掌握内存分配FF,BF,WF策略及实现的思路; 2)掌握内存回收过程及实现思路; 3)参考本程序思路,实现内存的申请、释放的管理程序,调试运行,总结程序设计中出现的问题并找出原因,写出实验报告。

3.实验过程: 创建进程: 删除其中几个进程:(默认以ff首次适应算法方式排列) Bf最佳适应算法排列方式: wf最差匹配算法排列方式: 4.实验心得: 明 实验中没有用到循环首次适应算法,但是对其他三种的描述还是很详细,总的来说,从实验中还是学到了很多。 5.程序源代码: #include #include #include #include

#define PROCESS_NAME_LEN 32 //进程名长度 #define MIN_SLICE 10 //最小碎片的大小#define DEFAULT_MEM_SIZE 1024 //内存大小 #define DEFAULT_MEM_START 0 //起始位置 /*内存分配算法*/ #define MA_FF 1 #define MA_BF 2 #define MA_WF 3 /*描述每一个空闲块的数据结构*/ struct free_block_type { }; /* /* { }; /* /* void display_menu(); int set_mem_size(); void set_algorithm(); void rearrange(int algorithm); int rearrange_WF(); int rearrange_BF(); int rearrange_FF(); int new_process(); int allocate_mem(struct allocated_block *ab);

实验三 存储管理指导

实验三存储管理 实验目的 1) 加深对存储管理的理解; 2) 掌握几种页面置换算法; 3) 通过实验比较各种置换算法的优劣。 实验要求 1) 编写程序完成实验内容; 2) 对测试数据进行分析; 3) 撰写实验报告。 实验内容 1) 定义为进程分配的物理块数; 2)定义进程运行所需访问的页面号; 3)定义页的结构; 4)模拟两种页面置换算法; 5)计算页面置换算法的命中率; 6)比较两种算法的优劣。 实验原理 1.虚拟存储 基于局部性原理,应用程序在运行之前,没有必要全部装入内存,仅须将那些当前要运行的少数页面或段先装入内存便可运行,其余部分暂留在盘上。程序在运行时,如果它所要访问的页(段)已调入内存,便可继续执行下去;但如果程序所要访问的页(段)尚未调入内存(称为缺页或缺段),此时程序应利用OS所提供的请求调页(段)功能,将它们调入内存,以使进程能继续执行下去。如果此时内存已满,无法再装入新的页(段),则还须再利用页(段)

的置换功能,将内存中暂时不用的页(段)调至盘上,腾出足够的内存空间后,再将要访问的页(段)调入内存,使程序继续执行下去。 2.页面置换算法 1)最佳(Optimal)置换算法 最佳置换算法是由Belady于1966年提出的一种理论上的算法。其所选择的被淘汰页面,将是以后永不使用的,或许是在最长(未来)时间内不再被访问的页面。采用最佳置换算法,通常可保证获得最低的缺页率。但由于人们目前还无法预知一个进程在内存的若干个页面中,哪一个页面是未来最长时间内不再被访问的,因而该算法是无法实现的,但可以利用该算法去评价其它算法。 2)最近最久未使用(LRU)置换算法 FIFO置换算法性能之所以较差,是因为它所依据的条件是各个页面调入内存的时间,而页面调入的先后并不能反映页面的使用情况。最近最久未使用(LRU)的页面置换算法,是根据页面调入内存后的使用情况进行决策的。由于无法预测各页面将来的使用情况,只能利用“最近的过去”作为“最近的将来”的近似,因此,LRU置换算法是选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间t,当须淘汰一个页面时,选择现有页面中其t值最大的,即最近最久未使用的页面予以淘汰。 LRU置换算法虽然是一种比较好的算法,但要求系统有较多的支持硬件。为了了解一个进程在内存中的各个页面各有多少时间未被进程访问,以及如何快速地知道哪一页是最近最久未使用的页面,须有两类硬件之一的支持:寄存器或栈。 a)寄存器 为了记录某进程在内存中各页的使用情况,须为每个在内存中的页面配置一个移位寄存器,可表示为R=R n-1R n-2R n-3… R2R1R0当进程访问某物理块时,要将相应寄存器的R n-1位置成1。此时,定时信号将每隔一定时间(例如100 ms)将寄存器右移一位。如果我们把n位寄存器的数看做是一个整数,那么,具有最小数值的寄存器所对应的页面,就是最近最久未使用的页面。 b)栈 可利用一个特殊的栈来保存当前使用的各个页面的页面号。每当进程访问某页面时,便将该页面的页面号从栈中移出,将它压入栈顶。因此,栈顶始终是最新被访问页面的编号,而栈底则是最近最久未使用页面的页面号。

虚拟内存删除

内存在计算机中的作用很大,电脑中所有运行的程序都需要经过内存来执行,如果执行的程序很大或很多,就会导致内存消耗殆尽。真难想象如果电脑没有内存将如何运行。为了解决这个问题,Windows中运用了虚拟内存技术,当然vista也不例外。即拿出一部分硬盘空间来充当内存使用,当内存占用完时,电脑就会自动调用硬盘来充当内存。虽然这样使用硬盘作虚拟内存读取速度相对于内存速度要逊色很多,但是终究是有效果的。举一个例子来说,如果电脑只有512MB物理内存的话,当读取一个容量为600MB 的文件时,就必须要用到比较大的虚拟内存,文件被内存读取之后就会先储存到虚拟内存,等待内存把文件全部储存到虚拟内存之后,跟着就会把虚拟内里储存的文件释放到原来的安装目录里了。 下面,就让我们一起来看看如何对虚拟内存进行设置吧。 具体步骤如下: (1).打开计算机"系统" (2).在左窗格中,单击“高级系统设置”。 (3).在“高级”选项卡上,在“性能”下,单击“设置”。 (4).单击“高级”选项卡,然后在“虚拟内存”下,单击

“更改”。 (5).清除“自动管理所有驱动器的页面文件大小”复选框。 (6).在“驱动器[卷标]”下,单击要更改的页面文件所在的驱动器。 (7).单击“自定义大小”,在“初始大小(MB)”或“最大大小(MB)”框中键入新的大小(以兆字节为单位),单击“设置”,然后单击“确定”。

如果你觉得比较的麻烦你可以使用上面的步骤,然后选择系统管理的大小即可。 这样可以通过虚拟内存来弥补的不足。如果你是在怕麻烦了直接再买个内存条插上好了。vista之家团队(https://www.doczj.com/doc/1e14082935.html,)(deepblue整理编辑)

实验4内存管理资料讲解

实验 4 内存管理

实验4内存管理 学校:FJUT 学号:3131903229 班级:计算机1302姓名:姜峰 注:其中LFU和NRU算法运行结果可能与其他人不同,只是实现方式不同,基本思路符合就可以。 .实验学时与类型 学时:2,课外学时:自定 实验类型:设计性实验二.实验目的 模拟实现请求页式存储管理中常用页面置换算法,理会操作系统对内存的 调度管理。 三?实验内容 要求:各算法要给出详细流程图以及执行结果截图。 假设有一程序某次运行访问的页面依次是: 0,124,3,4,5,1,2,5,1,2,3,4,5,6 ,请给出采用下列各页面置换算法时页面的换进换出情况,并计算各调度算法的命中率(命中率二非缺页次数/总访问次数),初始物理内存为空,物理内存可在4?20页中选择。 (1)FIFO :最先进入的页被淘汰; (2)LRU :最近最少使用的页被淘汰; (3)OPT :最不常用的页被淘汰;(选做) ⑷LFU :访问次数最少的页被淘汰(LFU)。(选做)

源代码: #i nclude #include #in elude #i nclude #defi ne MAXNUM 100 struct Phy_Memory{ //定义一个物理内存结构体 char Page; int time; }; char *OutPut; struct Phy_Memory *Phy_Page; void Print(char *PageStr,int Phy_PageNum,int absence){ // 打印图解函数int i,j; for(i=0;iPage!=*Temp;i++); if(i

虚拟内存设置是不是越大越好

虚拟内存设置是不是越大越好 虚拟内存帮助我们释放磁盘空间,需要是还能进行数据交换,那么有人问到虚拟内存是不是越大越好?下面是小编收集整理的虚拟内存如何设置最好,希望对大家有帮助~~ 虚拟内存介绍: 虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。 Windows 8/8.1 操作系统如出现开机时卡在Windows徽标页面,无法进入系统,必须强制关机再重启才能打开时,可适当调整虚拟内存设置解决。 虚拟内存设置最好的方法

方法/步骤 1虚拟内存设置步骤 右击计算机-属性-高级系统设置-高级-设置-高级-更改,选择系统管理的大小(推荐使用),点击确定。 2.电脑虚拟内存不是越大越好 电脑虚拟内存不是越大越好,虚拟内存大小不要超过你物理内存的1.5倍,内存4G或者以上的、不玩大型游戏的可以不设置,因为虚拟内存对于硬盘消耗太大。 在进行虚拟内存设置之前,对电脑进行全盘清理,尤其是电脑磁盘清理。可以观看小编的经验。c盘空间越来越小怎么完美清理 3.自定义 如果你的电脑内存1G,2G,你又要运行较大的程序,可以进行自定义大小设置,最大值不大于物理内存的1.5倍,也可以使用系统的推荐,初始大小设置成物理内存大小。

4.虚拟内存的删除 点击无分页文件,点击设置-确定 5.虚拟内存更改位置 把c盘的虚拟文件删除后,点击D盘,点击系统管理的大小,点击设置,点击确定

操作系统 内存管理实验报告

同组同学学号: 同组同学姓名: 实验日期:交报告日期: 实验(No. 4 )题目:编程与调试:内存管理 实验目的及要求: 实验目的: 操作系统的发展使得系统完成了大部分的内存管理工作,对于程序员而言,这些内存管理的过程是完全透明不可见的。因此,程序员开发时从不关心系统如何为自己分配内存,而且永远认为系统可以分配给程序所需的内存。在程序开发时,程序员真正需要做的就是:申请内存、使用内存、释放内存。其它一概无需过问。本章的3个实验程序帮助同学们更好地理解从程序员的角度应如何使用内存。 实验要求: 练习一:用vim编辑创建下列文件,用GCC编译工具,生成可调试的可执行文件,记录并分析执行结果,分析遇到的问题和解决方法。 练习二:用vim编辑创建下列文件,用GCC编译工具,生成可调试的可执行文件,记录并分析执行结果。 练习三:用vim编辑创建下列文件,用GCC编译工具,生成可调试的可执行文件,记录并分析执行结果。 改编实验中的程序,并运行出结果。 实验设备:多媒体电脑 实验内容以及步骤: 在虚拟机中编写好以下程序: #include #include #include int main(void) { char *str; /* 为字符串申请分配一块内存*/ if ((str = (char *) malloc(10)) == NULL) { printf("Not enough memory to allocate buffer\n"); return(1); /* 若失败则结束程序*/ } /* 拷贝字符串“Hello”到已分配的内存空间*/ strcpy(str, "Hello"); /* 显示该字符串*/ printf("String is %s\n", str); /* 内存使用完毕,释放它*/ free(str); return 0; } 调试过后得出的结果截图如下:(由图可看出我将此程序以aa.c为文件名保存,调试后出现aa1文件,调试结果出现语句“String is Hello”)

存储管理实验报告.doc

存储管理实验报告

北方工业大学 《计算机操作系统》实验报告 实验名称存储管理实验序号 2 实验日期2013.11.27实验人 一、实验目的和要求 1.请求页式存储管理是一种常用的虚拟存储管理技术。本实验目的 是通过请求页式存储管理中页面置换算法的模拟设计,了解虚拟存储 技术的特点,掌握请求页式存储管理的页面置换算法。 二、相关背景知识 1.随机数产生办法 关于随机数产生办法, Linux 或 UNIX 系统提供函数 srand() 和 rand() ,分 别进行初始化和产生随机数。 三、实验内容 (1).通过随机数产生一个指令序列,共320条指令。指令的地址按下述原则生成: 1.50% 的指令是顺序执行的; 2.25% 的指令是均匀分布在前地址部分; 3.25% 的指令是均匀分布在后地址部 分;具体的实施方法是: 1.在[0, 319]的指令地址之间随机选取一起点 m; 2.顺序执行一条指令,即执行地址为 m+1 的指令; 3.在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’; 4.顺序执行一条指令,其地址为 m’+1; 5.在后地址 [m ’+2, 319]中随机选取一条指令并执行; 6.重复上述步骤 1~5,直到执行 320 次指令。 (2)将指令序列变换成页地址流,设 1.页面大小为 1K ; 2.用户内存容量为 4 页到 32 页; 3.用户虚存容量为 32K 。 在用户虚存中,按每 K 存放 10 条指令排列虚存地址,即 320 条指令在虚存 中存放的方式为: 第 0 条至第 9 条指令为第 0 页(对应虚存地址为 [0, 9]); 第 10 条至第 19 条指令为第 1 页(对应虚存地址为 [10, 19]); 第 310 条至第 319 条指令为第 31 页(对应虚存地址为 [310,319]); 按以上方式,用户指令可以组成 32 页。 (3)计算并输出下述各种算法在不同内存容量下的命中率。

相关主题
文本预览
相关文档 最新文档