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

2024-03-14

众所周知,Windows 应用程序在 32 位系统上通常有 2Gb 的私有地址空间。使用 /3Gb 开关可以将该空间扩展到 3Gb。

操作系统自行保留剩余的 4Gb。

我的问题是为什么?

在内核模式下运行的代码(即设备驱动程序代码)有自己的地址空间。为什么操作系统除了独享 4Gb 地址空间之外,还要为每个用户模式进程保留 2Gb?

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

如果您能向我解释一下为什么操作系统占用每个用户模式进程的 2Gb(或 1Gb)空间如此重要。


两个不同的用户进程具有不同的虚拟地址空间。由于虚拟↔物理地址映射不同,TLB http://en.wikipedia.org/wiki/Translation_lookaside_buffer当上下文从一个用户进程切换到另一个用户进程时,缓存会失效。这是非常昂贵的,因为如果没有缓存在 TLB 中的地址,任何内存访问都将导致错误和遍历PTE http://en.wikipedia.org/wiki/Page_tables.

系统调用涉及两个上下文切换:用户→内核,然后内核→用户。为了加快速度,通常会保留顶部 1GB 或 2GB 的虚拟地址空间供内核使用。由于虚拟地址空间在这些上下文切换中不会发生变化,因此不需要 TLB 刷新。这是由每个 PTE 中的用户/管理员位启用的,这确保内核内存只能在内核空间中访问;即使页表相同,用户空间也无权访问。

如果硬件支持两个独立的 TLB,其中一个专门供内核使用,那么这种优化将不再有用。但是,如果您有足够的专用空间,那么制作一个更大的 TLB 可能更值得。

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


Times have changed since this question was originally asked and answered: 64-bit operating systems are now much more prevalent. In current OSes on x86-64, virtual addresses from 0 to 247-1 (0-128TB) are allowed for user programs while the kernel permanently resides within virtual addresses from 247×(217-1) to 264-1 (or from -247 to -1, if you treat addresses as signed integers).

What happens if you run a 32-bit executable on 64-bit Windows? You would think that all virtual addresses from 0 to 232 (0-4GB) would easily be available, but in order to avoid exposing bugs in existing programs, 32-bit executables are still limited to 0-2GB unless they are recompiled with /LARGEADDRESSAWARE. For those that are, they get access to 0-4GB. (This is not a new flag; the same applied in 32-bit Windows kernels running with the /3GB switch, which changed the default 2G/2G user/kernel split to 3G/1G, although of course 3-4GB would still be out of range.)

可能存在哪些类型的错误?举个例子,假设您正在实现快速排序并有两个指针,a and b指向数组的开头和结尾。如果您选择中间作为枢轴(a+b)/2,只要两个地址都在2GB以下就可以,但如果都在2GB以上,那么加法会遇到整数溢出,结果会超出数组。 (正确的表达是a+(b-a)/2.)

顺便说一句,32 位 Linux 具有默认的 3G/1G 用户/内核分割,历史上运行的程序的堆栈位于 2-3GB 范围内,因此任何此类编程错误都可能很快被清除。 64 位 Linux 允许 32 位程序访问 0-4GB。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Windows 为其系统地址空间保留 1Gb(或 2Gb)? 的相关文章

随机推荐