承诺与保留内存

时间:2019-04-20 17:39:47

标签: memory memory-management

根据“ Windows Internals,第1部分”(第7版,Kindle版):

  

进程虚拟地址空间中的页面是空闲,保留,已提交或可共享的。

仅在reservedcommitted页面上,第一种类型在同一本书中进行了描述:

  

保留内存意味着预留一系列连续的虚拟地址以供将来使用(例如数组),同时消耗可忽略的系统资源,然后在应用程序运行时根据需要提交部分保留的空间。或者,如果事先知道大小要求,则进程可以保留并提交相同的函数调用。

保留或提交都将首先使您在VAD(虚拟地址描述符)中获得条目,但是这两种操作都不会触及PTE(页表条目)结构。在Windows 8.1 but not anymore之前,PTE的保留成本很高。

如上所述,reserved表示在OS级别阻止虚拟地址范围,而不是阻止物理内存或分页文件空间。操作系统未在提交限制中包含此内容,因此当需要分配此内存时,您可能会感到惊讶。重要的是要注意,保留是从过程地址空间的角度进行的。这并不是说保留了任何物理资源-没有针对RAM空间或页面文件的标记“无空缺”。

与土地图的类比可能缺少某些内容:将reserved作为木杆所包围的土地面积,这样就让其他人现在就拥有了该土地。但是committed呢?不能在已经建造了建筑物(例如房屋)的土地上进行,因为那些建筑物需要PTE,而由于我们还没有任何东西,因此那里还没有PTE。只有在触摸committed数据时,才会构建PTE,这将使页面可用于该过程。

主要问题是committed存储器(至少在其初始状态下)在功能上非常类似于reserved存储器。这只是VAD内被封锁的区域。尝试触摸其中一个地址,您将获得reserved地址的访问冲突异常:

  

尝试访问空闲或保留的内存会导致访问冲突异常,因为该页面未映射到可以解析引用的任何存储空间

...以及committed的初始页面错误(立即创建所需的PTE条目)。

回到土地类比,一旦房屋建造完毕,那片土地仍然是committed。但这有点特殊,因为在最初的铁锹被挖出开始建造之前,当原始草还在那里时committed仍然存在。它类似于保留补丁的状态。也许最好将其视为适合建造的地形。例如,您有建造许可证(尽管您可能永远不会在那片土地上建造出如此多的墙)。

使用一种内存而不使用另一种内存的原因是什么?至少有一个:操作系统保证将来有可能分配committed内存,但是除了阻塞该进程的地址外,不能保证reserved内存有任何空间空间范围。 committed内存的唯一缺点是可能需要扩展一个或多个分页文件的大小,以便能够使提交限制考虑到最近分配的块,因此请求者应要求使用一部分将来所有数据中,操作系统都可以提供对它们的访问。

我真不敢想象土地比喻如何捕捉“保证”的细节。毕竟,reserved斑块也物理存在,与处于原始状态的committed一样被同一草覆盖。

堆栈是reservedcommitted内存一起使用的另一种情况:

  

创建线程后,内存管理器会自动保留预定数量的虚拟内存,默认情况下为1 MB。[...]尽管保留了1 MB,但只会提交堆栈的第一页[ ...]    以及保护页面。当线程的堆栈增长到足以触及保护页面时,就会发生异常,从而导致尝试分配另一个保护。通过这种机制,用户堆栈不会立即消耗所有1 MB的已提交内存,而是随需求增长。”

有一个答案here,说明了为什么要使用reserved而不是committed的内存。它涉及存储连续扩展的数据-实际上是上述堆栈模型-并在需要时具有可用的特定绝对地址范围(尽管我不确定为什么要在一个进程中这样做)。

好吧,我实际上在问什么?

  1. 对于reserved / committed概念,有什么好比喻?
  2. 除上述原因外,还有其他原因会导致 使用reserved内存?有什么有趣的用例时 依靠reserved记忆是明智之举吗?

1 个答案:

答案 0 :(得分:1)

您的问题碰到逻辑内存转换和虚拟内存转换之间的差异。尽管CPU文档喜欢将这两个概念混为一谈,但实际上它们是不同的。

如果查看逻辑内存转换,则页面只有两种状态。使用您的术语,它们是免费和承诺的。空闲页面是指没有映射到物理页面框架的页面,而COMMITTED页面则具有这种映射。

在虚拟内存系统中,操作系统必须在辅助存储中维护地址空间的副本。如何完成此操作取决于操作系统。通常,进程会将其映射到几个不同的文件以进行辅助存储。操作系统将地址空间划分为通常称为SECTION的部分。

例如,代码和只读数据实际上可以作为一个或多个SECTIONS存储在可执行文件中。共享库中的代码和静态数据可以分别位于分页到共享库的不同部分中。您可能有一个映射到使用该内存的进程的共享文件,该内存可以由形成另一个部分的多个进程访问。大多数读/写数据可能在一个或多个部分的页面文件中。操作系统如何跟踪虚拟存储每个数据部分的位置取决于系统。

对于Windows,它给出了以下术语之一的定义:可共享。可共享部分是可以在其中将一系列地址映射到不同进程的不同逻辑进程的地址。

然后保留您的上学期。如果您查看Windoze VirtualAlloc函数文档,

https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc

您可以看到(在您的选择中)您可以保留或提交。如果保留,则将创建虚拟内存部分,该部分没有映射到物理内存。

此RESERVE / COMMIT模型特定于Windows(尽管其他操作系统也可以这样做)。可能的原因是节省磁盘空间。开发Windoze NT时,仍在使用600MB大小的洗衣机。

在当今的64位地址空间中,此系统非常适合(如您所说)扩展数据。从理论上讲,用于堆栈溢出的异常处理程序可以简单地扩展堆栈。保留4GB内存所占用的资源不会比保留单个页面多(这在32位系统中不可行,请参见上文)。如果您有20个线程,则可以有效地保留堆栈空间。

  

对于保留/提交的概念,有什么好比喻?

有人会说RESERVE就像是购买期权,而COMMIT则在行使期权。

  

除上述原因外,还有其他原因要求使用保留内存吗?使用保留内存是明智之举吗?

恕我直言,最有可能在不提交的情况下进行保留的地方是用于创建堆栈和堆,其中前者最为重要。