您的位置:首页 > 其它

Windows的内存结构

2007-09-06 18:21 204 查看
进程的虚拟地址空间



每个进程都被赋予它自己的虚拟地址空间。对于32
位进程来说,这个地址空间是4GB
,对于64
位进程来说,这个地址空间是16EB
(1018
字节).
每个进程可以接收它自己的私有的地址空间,因此当进程中的一个线程正在运行时,该线程可以访问只属于它的进程的内存。属于所有其他进程的内存则隐藏着,并且不能被正在运行的线程访问。这是个虚拟地址空间,不是物理地址空间。该地址空间只是内存地址的一个范围。在你能够成功地访问数据而不会出现违规访问之前,必须赋予物理存储器,或者将物理存储器映射到各个部分的地址空间。

保留地址空间中的区域



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

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


如果想保留一个10KB
的地址空间区域,系统将自动对你的请求进行四舍五入,使保留的地址空间区域的大小是页面大小的倍数。这意味着,在x86
平台上,系统将保留一个12KB
的区域。当你的程序算法不再需要访问已经保留的地址空间区域时,该区域应该被释放。这个过程称为释放地址空间的区域,它是通过调用VirtualFree
函数来完成的。

提交地址空间区域中的物理存储器



若要使用已保留的地址空间区域,必须分配物理存储器,然后将该物理存储器映射到已保留的地址空间区域。这个过程称为提交物理存储器。
物理存储器总是以页面的形式来提交的。若要将物理存储器提交给一个已保留的地址空间区域,也要调用VirtualAlloc
函数。当将物理存储器提交给地址空间区域时,不必将物理存储器提交给整个区域。例如,可以保留一个64KB
的区域,然后将物理存储器提交给该区域中的第二和第四个页面。

当你的程序算法不再需要访问保留的地址空间区域中已提交的物理存储器时,该物理存储器应该被释放。这个过程称为回收物理存储器,它是通过VirtualFree
函数来完成的。

物理存储器与页文件



在较老的操作系统中,物理存储器被视为计算机拥有的RAM
的容量。今天的操作系统能够使得磁盘空间看上去就像内存一样。磁盘上的文件通常称为页文件
,它包含了可供所有进程使用的虚拟内存。

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

现在,进程中的一个线程试图访问进程的地址空间中的一个数据块时,将会发生两种情况:

在第一种情况中,线程试图访问的数据是在RAM
中。在这种情况下,CPU
将数据的虚拟内存地址映射到内存的物理地址中,然后执行需要的访问。

在第二种情况中,线程试图访问的数据不在RAM
中,而是存放在页文件中的某个地方。

1)
这时,试图访问就称为页面失效, CPU
将把试图进行的访问通知操作系统。

2)
这时操作系统就寻找RAM
中的一个内存空页。如果找不到空页,系统必须释放一个空页。如果一个页面尚未被修改,系统就可以释放该页面。但是,如果系统需要释放一个已经修改的页面,那么它必须首先将该页面从RAM
拷贝到页交换文件中.

3)
然后系统进入该页文件,找出需要访问的数据块,并将数据加载到空闲的内存页面。

4)
然后,操作系统更新它的用于指明数据的虚拟内存地址现在已经映射到RAM
中的相应的物理存储器地址中的表。

5)
这时CPU
重新运行生成初始页面失效的指令,但是这次CPU
能够将虚拟内存地址映射到一个物理RAM
地址,并访问该数据块。

系统需要将内存页面拷贝到页文件并反过来将页文件拷贝到内存页面的次数越多,你的硬盘倒腾的次数就越多,系统运行得越慢(倒腾意味着操作系统要花费更多的时间将页面从内存中转出转进,而不是将时间用于程序的运行)。因此,通过给你的计算机增加更多的RAM,
就可以减少运行应用程序所需的倒腾次数,这就必然可以大大提高系统的运行速度。所以必须遵循一条基本原则,那就是要让你的计算机运行得更块,增加更多的RAM
。实际上,在大多数情况下,若要提高系统的运行性能,增加RAM
比提高CPU
的速度所产生的效果更好。

不在页文件中维护的物理存储器[
内存映射文件]



当启动一个应用程序的时候,系统将打开该应用程序的.exe
文件,确定该应用程序的代码和数据的大小。然后系统要保留一个地址空间的区域,并指明与该区域相关联的物理存储器是在.exe
文件本身中。即系统并不是从页文件中分配地址空间,而是将.exe
文件的实际内容即映像用作程序的保留地址空间区域。当然,这使应用程序的加载非常迅速,并使页文件能够保持得非常小。

当硬盘上的一个程序的文件映像(这是个
.exe
文件或
DLL
文件)用作地址空间的区域的物理存储器时,它称为内存映射文件
。当一个
.exe
文件或
DLL
文件被加载时,系统将自动保留一个地址空间的区域,并将该文件映像映射到该区域中。但是,系统也提供了一组函数,使你能够将数据文件映射到一个地址空间的区域中。

保护属性



已经分配的物理存储器的各个页面可以被赋予不同的保护属性。

PAGE_NOACCESS

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

PAGE_READONLY

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

PAGE_READWRITE

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

PAGE_EXECUTE

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

PAGE_EXECUTE_READ

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

PAGE_EXECUTE_READWRITE

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

PAGE_WRITECOPY

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

PAGE_EXECUTE_WRITECOPY

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

当使用
VirtualAlloc
函数来保留地址空间或者提交物理存储器时,不应该传递
PAGE_WRITECOPY

PAGE_EXECUTE_READWRITE
。如果传递的话,将会导致
VirtualAlloc
调用的失败。对
GetLastError
的调用将返回
ERROR_INVALID_PARAMETER
。当操作系统映射
.exe

DLL
文件映像时,这两个属性将被操作系统使用。

数据对齐的重要性



数据对齐并不是操作系统的内存结构的一部分,而是
CPU
结构的一部分。当
CPU
访问正确对齐的数据时,它的运行效率最高。当数据大小的数据模数的内存地址是
0
时,数据是对齐的。例如,
WORD
值应该总是从被
2
除尽的地址开始,而
DWORD
值应该总是从被
4
除尽的地址开始,如此等等。当
CPU
试图读取的数据值没有正确对齐时,
CPU
可以执行两种操作之一。即它可以产生一个异常条件,也可以执行多次对齐的内存访问,以便读取完整的未对齐数据值。显然,如果
CPU
执行多次内存访问,应用程序的运行速度就会放慢。在最好的情况下,系统访问未对齐的数据所需要的时间将是访问对齐数据的时间的两倍,不过在有些情况下,访问时间可能更长。为了使应用程序获得最佳的运行性能,编写的代码必须使数据正确地对齐。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: