根据">Windows Internals,Part 1"(第7版,Kindle版本):
进程虚拟地址空间中的页面可以是空闲的、保留的、已提交的或可共享的。
只关注reserved
和committed
页面,第一种类型在同一本书中描述:
内存意味着留出一系列连续的虚拟地址以供将来可能使用(例如阵列),同时消耗可忽略不计的系统资源,然后在应用程序运行时根据需要提交部分保留空间。或者,如果事先知道大小要求,则进程可以在同一函数调用中保留和提交。
保留或提交最初都会在 VAD(虚拟地址描述符)中获取条目,但这两个操作都不会触及 PTE(页表条目)结构。它曾经在Windows 8.1之前花费PTE进行预订,但现在不再了。
如上所述,reserved
意味着阻止一系列虚拟地址,而不是在操作系统级别阻止物理内存或分页文件空间。操作系统不会在提交限制中包含此内容,因此当需要分配此内存时,您可能会感到惊讶。请务必注意,保留是从进程地址空间的角度进行的。这并不是说保留了任何物理资源 - 没有针对 RAM 空间或页面文件的"无空缺"标记。
与地块的类比可能缺少一些东西:将reserved
作为被木杆包围的土地区域,从而让其他人现在土地被占用。但是committed
呢?它不可能是已经建造结构(例如房屋)的土地,因为这些需要 PTE,而那里还没有,因为我们还没有访问任何东西。只有在接触committed
数据时,才会构建 PTE,这将使页面可供流程使用。
主要问题是committed
记忆 - 至少在其初始状态下 - 在功能上reserved
内存非常相似。这只是VAD中被封锁的区域。尝试触摸其中一个地址,您将获得reserved
地址的访问冲突异常:
尝试访问可用内存或保留内存会导致访问冲突异常,因为页面未映射到可以解析引用的任何存储
。以及committed
的初始页面错误(紧随其后的是要创建的所需 PTE 条目)。
回到土地类比,一旦房屋建成,那块土地仍然committed
。然而,这有点奇怪,因为在挖掘第一把铲子开始施工之前,当原始草在那里时,它仍然committed
。它类似于与保留补丁相同的状态。也许最好把它想象成适合建设的地形。例如,您有建造许可证(尽管您可能永远不会在那块土地上建造那么多的墙)。
使用一种类型的内存与另一种内存的原因是什么?至少有一个:操作系统保证将来会有空间分配committed
内存,但除了阻止该进程的地址空间范围之外,不保证reserved
内存的任何内容。committed
内存的唯一缺点是可能需要扩展一个或多个分页文件的大小,以便能够使提交限制考虑到最近分配的块,因此如果请求者要求将来使用部分所有数据,操作系统可以提供对它的访问。
我真的想不出土地类比如何捕捉到"保证"这个细节。毕竟,reserved
地块在物理上也存在,被原始状态下的committed
相同的草覆盖。
堆栈是同时使用reserved
和committed
内存的另一种方案:
创建线程时,内存管理器会自动保留预定数量的虚拟内存,默认情况下为 1 MB。...]尽管保留了 1 MB,但只会提交堆栈的第一页 [...] 以及一个保护页面。当线程的堆栈变得足够大以接触保护页时,会发生异常,导致尝试分配另一个保护。通过这种机制,用户堆栈不会立即消耗所有 1 MB 的已提交内存,而是随着需求的增长而增长。
这里有一个答案,可以解决为什么人们想要使用reserved
内存而不是committed
。它涉及存储不断扩展的数据 - 这实际上是上面描述的堆栈模型 - 并在需要时提供特定的绝对地址范围(尽管我不确定为什么人们想要在进程中这样做)。
好吧,我实际上在问什么?
- 对于
reserved
/committed
概念来说,什么是很好的类比? - 除上述原因外,任何其他原因将强制要求 使用
reserved
内存?是否有任何有趣的用例,当 诉诸reserved
记忆是明智之举?
您的问题涉及逻辑内存转换和虚拟内存转换之间的区别。虽然 CPU 文档喜欢将这两个概念混为一谈,但它们在实践中是不同的。
如果您查看逻辑内存转换,页面只有两种状态。使用您的术语,它们是免费且承诺的。空闲页面是没有映射到物理页面框架的页面,而 COMMIT 页面具有这样的映射。
在虚拟内存系统中,操作系统必须在辅助存储中维护地址空间的副本。如何执行此操作取决于操作系统。通常,进程将映射到多个不同的文件以进行辅助存储。操作系统将地址空间划分为通常称为 SECTION 的内容。
例如,代码和只读数据可以虚拟地存储为可执行文件中的一个或多个 SECTIONS 。共享库中的代码和静态数据可能分别位于分页到共享库的不同部分中。您可能有一个映射到共享文件的进程,该进程使用内存,该内存可由构成另一个部分的多个进程访问。大多数读/写数据可能位于一个或多个部分的页面文件中。操作系统如何跟踪其虚拟存储每个数据部分的位置取决于系统。
对于窗口,这给出了其中一个术语的定义:可共享。可共享部分是可以将一系列地址映射到不同(或可能相同)逻辑地址的不同进程的部分。
然后保留您的最后一个学期。如果您查看Windows的VirtualAlloc
函数文档,您可以看到(在您的选项中)您可以保留或提交。如果保留,则正在创建与物理内存没有映射的虚拟内存部分。
此 RESERVE/COMMIT 模型是特定于 Windows 的(尽管其他操作系统可能会这样做)。可能的原因是节省磁盘空间。当Windows NT被开发出来时,洗衣机大小的600MB驱动器仍在使用。
在 64 位地址空间的这些日子里,这个系统非常适合(如你所说)扩展数据。理论上,堆栈溢出的异常处理程序可以简单地扩展堆栈。保留 4GB 内存不会比保留单个页面占用更多的资源(这在 32 位系统中是不切实际的 - 见上文)。如果您有 20 个线程,则可以高效保留堆栈空间。
对于保留/承诺的概念来说,什么是很好的类比?
有人可能会说RESERVE就像购买期权来购买,而COMMIT正在行使期权。
除了上面描述的原因之外,还有其他原因会强制使用保留内存吗?当诉诸保留内存是明智之举时,是否有任何有趣的用例?
恕我直言,最有可能在不提交的情况下保留的地方是创建堆栈和堆,前者是最重要的。