为什么Windows为其系统地址空间预留1Gb(或2 Gb)?

这是一个已知的事实,Windows应用程序通常在32位系统上具有2Gb的私有空间。该空间可以通过/ 3Gb开关扩展到3Gb。

操作系统保留了4Gb的剩余部分。

我的问题是为什么?

在内核模式下运行的代码(即设备驱动程序代码)具有自己的地址空间。为什么在独占的4Gb地址空间之上,操作系统仍然希望保留每个用户模式进程的2Gb?

我以为原因是用户模式和内核模式之间的转换。例如,调用NtWriteFile将需要内核调度程序的地址(因此为什么系统在每个应用程序中保留2Gb)。但是,使用SYSENTER,系统服务号码不足以让内核模式的代码知道哪个功能/服务被调用

如果你能澄清一下,为什么操作系统对每个用户模式进程采取2Gb(或1Gb)这么重要,我会感激的。

谢谢。

两个不同的用户进程具有不同的虚拟地址空间。因为虚拟的物理地址映射是不同的,所以当将上下文从一个用户进程切换到另一个用户进程时, TLB高速缓存无效。这是非常昂贵的,因为没有在TLB中缓存的地址,任何内存访问将导致 PTE的故障和散步。

Syscalls涉及两个上下文切换:用户→内核,然后是内核→用户。为了加快速度,通常保留最高的1GB或2GB虚拟地址空间供内核使用。因为虚拟地址空间在这些上下文切换中不会改变,所以不需要TLB刷新。这是由每个PTE中的用户/管理员位启用的,这确保内核存储器仅在内核空间中可访问;即使页表相同,用户空间也无法访问。

如果有两个单独的TLB的硬件支持一个专门用于内核使用,那么这个优化将不再有用。但是,如果您有足够的空间来投入使用,那么制作一个更大的TLB可能更有价值。

Linux on x86曾经支持一种称为“4G / 4G分割”的模式。在这种模式下,用户空间可以完全访问整个4GB的虚拟地址空间,内核还具有完整的4GB虚拟地址空间。如上所述,成本是每个系统调用需要一个TLB刷新,以及更复杂的例程以在用户和内核内存之间复制数据。这一点已经被测量到达30%的性能损失。

时间已经改变,因为这个问题最初被提出和回答:64位操作系统现在更加普遍。在x86-64上的当前操作系统中,用户程序允许从0到247-1(0-128TB)的虚拟地址,而内核永久驻留在从247×(217-1)到264-1(或从 – 247到-1,如果将地址视为有符号整数)。

如果您在64位Windows上运行32位可执行文件,会发生什么?您会认为所有虚拟地址从0到232(0-4GB)将很容易可用,但是为了避免在现有程序中显示错误,32位可执行文件仍然限制在0-2GB,除非它们重新编译为/ LARGEADDRESSAWARE 。对于那些,他们可以访问0-4GB。 (这不是一个新的标志;同样适用于运行/ 3GB开关的32位Windows内核,它将认的2G / 2G用户/内核分裂更改为3G / 1G,尽管3-4GB仍然会出现的范围。)

可能有什么种类的错误?例如,假设您正在实现快速排序,并且有两个指针,a和b指向数组的开头和结尾。如果用(ab)/ 2选择中间作为枢轴,只要这两个地址都低于2GB,它就可以工作,但是如果它们都在上面,那么加法将会遇到整数溢出,结果将在阵列。 (正确的表达式是a(b-a)/ 2))

除此之外,32位Linux与其认的3G / 1G用户/内核拆分,历来是运行程序,其堆栈位于2-3GB范围内,因此任何此类编程错误都可能会被快速刷新。 64位Linux提供32位程序访问0-4GB。

相关文章

Windows2012R2备用域控搭建 前置操作 域控主域控的主dns:自...
主域控角色迁移和夺取(转载) 转载自:http://yupeizhi.blo...
Windows2012R2 NTP时间同步 Windows2012R2里没有了internet时...
Windows注册表操作基础代码 Windows下对注册表进行操作使用的...
黑客常用WinAPI函数整理之前的博客写了很多关于Windows编程的...
一个简单的Windows Socket可复用框架说起网络编程,无非是建...