windows核心编程系列13---Windows内存体系结构

1、进程的虚拟地址空间

每个进程都有自己的虚拟地址空间。对于32位的进程,这个地址空间的大小是4GB,这是因为32位的指针可以表示从0x00000000到0xFFFFFFFF之间的任一值。对于64位的,地址空间大小为16TB。


因为每个进程都有自己专有的地址空间,当进程中的个线程运行时,它们只能访问属于该进程的内存。线程即看不到属于其他线程的内存,也无法访问它们。


在Windows中,正在运行的线程看不到属于操作系统本身的内存,这意味着他不能无意间访问到操作系统的数据。


虚拟地址空间不是物理存储器。还需要把物理存储器分配或者映射到相应的地址空间,否则将导致访问违规(access voilation)



2、虚拟地址空间的分区


2.1、空指针赋值空间

这一分区是进程地址空间中从0x000000000x0000FFFF的闭区间,保留该分区的目的是为了帮助程序员捕获对空指针的赋值。


如果进程中的线程试图读取或者写入位于这一分区内的内存地址,就会引发访问违规。


没有任何办法可以让我们分配到位于这一地址空间内的虚拟内存,即使是使用Win32应用程序编程接口API也不例外。


2.2、用户模式分区


在windows中,所有exe和dll都载入到这一区域,每个进程都有可能将这些dll载入到这一分区内的不同地址(虽然这种可能性很小),系统同时会把该进程可以访问的所有内存映射文件映射到这一分区。


1、在x86 Windows下得到更大的用户模式分区

x86版的windows提供了一种模式来增大用户模式分区,最多不超过3GB。需要对windows中的启动配置数据(boot configuration data 简称BCD)进行设定,并重新启动机器。有关BCD的更多信息,请查阅:http://www.microsoft.com/whdc/system/platform/firmware/bcd.mspx


当系统即将运行一个应用程序时,它会检查应用程序在链接时是否使用了/LARGEADDRESSAWARE链接器开关。如果是,则相当于应用程序在声明它会充分利用大用户模式地址空间,而不会对内存地址进行任何不当的操作。反之,如果应用程序在链接时没用使用/LARGEADDRESSAWARE开关,那么操作系统会保留用户模式分区中2GB以上到内核模式开始处的整个部分。这样,由于所有分配到的内存地址的最高位都是0,因此避免了应用程序对该位做出错误的解释。



2、在64位Windows下得到2GB用户模式分区

为了能让32位程序在64位系统下运行,系统使用地址空间沙箱(address space sandbox),即进程地址空间被限制在最底部的2GB中,相当于把一个高33位都为0的64位地址截断为32位地址。


在默认情况下, 当运行一个64位应用程序时,系统会保留用户模式地址空间中位于地址0x0000000080000000之后的所有部分,这就确保了所有内存都分配自64位地址空间中的最底部的2GB。为了让64位应用程序能够访问整个用户模式分区,必须用/LARGEADDRESSAWARE链接器开关来链接应用程序。


操作系统会在创建进程的64位地址空间时检查可执行文件的/LARGEADDRESSAWAR标志,对DLL来说,系统会忽略该标志,所有DLL必须经过正确编写,以便能够在4TB用户模式分区的情况下正常运行,否则其结果将不可预料。


3、内核模式分区

这一分区是操作系统代码的驻地。与线程调度。内存管理、文件系统支持、网络支持以及设备驱动程序相关的代码都载入到该部分。


3、地址空间中的区域

当系统创建一个进程并赋予它地址空间时,可用地址空间中的大部分都是闲置的(free)或者尚未分配的(unallocated)。为了使用这些地址空间,我们必须调用 VirualAlloc来分配其中的区域(region)。分配区域的操作称为 预定(reserving)。

分配粒度(allocation granularity):区域预定的基本单位。系统会确保区域的 起始地址正好是分配粒度的整数倍。分配粒B度会根据不同的cpu平台而有所不同。一般都是 64KB


当预定一个区域时,系统会确保区域的大小正好是 系统页面大小的整数倍。页面是一个内存单元,系统通过它来管理内存。页面大小与cpu相关。x86和x64系统的页面大小是 4KB,而IA-64系统使用的页面大小为8KB。

4、给区域调拨物理存储器


为了使用所预定的地址空间区域,我们还必须分配物理存储器,并将存储器映射到所预定的区域。这个过程称为 调拨(commiting)物理存储器。物理存储器始终都以页面为单位来调拨,可以通过VirualAlloc函数来将物理存储器调拨给所预定的区域。

当我们调拨物理存储器时,并不需要给整个区域调拨物理存储器。可以只给其中特定的页面调拨。

不使用时,应该释放物理存储器。称为 撤销调拨(decommiting)物理存储器。通过调用 VirualFree函数来完成。

5、物理存储器和页交换文件


当今的操作系统让磁盘空间看起来像内存一样。磁盘上的文件一般被称为 页交换文件(paging file),其中包含虚拟内存,可供任何进程使用。

下面流程图简单示意系统如何把虚拟地址转换为物理存储器地址:


当把一个程序位于硬盘上的文件映像(即一个.exe或.dll文件)用作地址空间区域对应的物理存储器时,我们称这个文件映像为 内存映射文件(memory mapped file)


当用户执行一个应用程序时,系统会打开该应用程序对应的.exe文件并计算出应用程序的代码和数据的大小。然后系统会预定一块地址空间,并注明与该区域相关联的物理存储器就是.exe文件本身。这样一来,不但载入程序非常快,而且页交换文件也可以保持一个合理大小。


6、页面保护属性






6.1、写时复制


Windows支持一种机制,允许两个或两个以上的程序共享同一块存储器。为了避免由于莫一个程序修改了存储器导致的混乱。操作系统会给共享的存储页面指定写时复制属性。当系统把一个.exe或.dll映射到一个地址空间的时候,系统会计算有多少页面是可写的。(通常,包含代码的页面被标记为PAGE_EXECUTE_READ,而包含数据的页面被标记为PAGE_READWRITE)然后系统会从页交换文件中分配存储空间来容纳这些可写页面。除非应用程序真的写入页面,否则不会用到页交换文件中的存储器。

当线程试图写入一个共享页面时,系统会介入并执行下面的操作:
(1)系统在内存中找到一个闲置页面。注意,该闲置页面的后备页面来自页交换文件,它是系统最初将模块映射到进程的地址空间时分配的。由于系统在第一次进行映射的时候分配了所有可能需要的页交换文件空间,这一步不可能失败。
(2)系统把线程想要修改的页面内容复制到在第一步找到的闲置页面。系统会给闲置页面指定PANGE_READWRITE或PAGE_EXECUTE_READWRITE保护属性,系统不会对原始页面的保护属性和数据做任何修改。
(3)然后,系统更新进程的页面表,这样一来,原来的虚拟地址现在就对应到内存中的一个新的页面了。
系统执行这些步骤后,进程就可以访问他自己的副本了。


7、数据对其的重要性

相较于操作系统的内存体系结构,数据对齐更多的是CPU体系结构的一部分。

只有当访问已对齐的数据时,CPU的执行效率才最高。

把数据的地址模除数据的大小,如果结果为0,那么数据就是对齐的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞天红猪侠001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值