C/C++|推动Windows的限制(虚拟内存)
在我推出Windows的限制后,我讨论了物理内存限制,包括由许可,实现和驱动程序兼容性施加的限制。这是整个推动限制系列的索引。虽然他们可以独立存在,但他们认为你是按顺序阅读的。
推动Windows的限制:物理内存这一次我把注意力转移到另一个基本的资源,虚拟内存。虚拟内存将程序的内存视图从系统的物理内存中分离出来,因此操作系统决定何时以及如何将程序的代码和数据存储在物理内存中以及何时将其存储在文件中。虚拟内存的主要优点是它允许更多的进程并行执行,否则可能适合物理内存。
推动Windows的限制:虚拟内存
推动Windows的限制:分页和非分页池
推动Windows的限制:进程和线程
推动Windows的限制:把手
推动Windows的限制:USER和GDI对象 - 第1部分
推动Windows的限制:USER和GDI对象 - 第2部分
尽管虚拟内存具有与物理内存限制相关的限制,但是虚拟内存具有来自不同来源的限制,并且根据消费者而不同。例如,虚拟内存限制适用于运行应用程序,操作系统和整个系统的单个进程。记住这一点很重要,就像虚名一样,虚拟内存与物理内存没有直接的联系。Windows为文件高速缓存分配一定数量的虚拟内存并不指定它在物理内存中实际缓存了多少文件数据; 它可以是从没有到超过可通过虚拟内存寻址的数量的任何数量。
处理地址空间
每个进程都有自己的虚拟内存,称为地址空间,将其执行的代码映射到代码引用和处理的数据中。32位进程使用32位虚拟内存地址指针,它为32位进程可以处理的虚拟内存量创建4GB(2 ^ 32)的绝对上限。但是,操作系统可以在不改变地址空间的情况下引用自己的代码和数据以及当前正在执行的进程的代码和数据,使得在每个进程的地址空间中都可以看到它的虚拟内存。默认情况下,Windows的32位版本在系统和活动进程之间平均分配进程地址空间,每个进程限制为2GB:
文章图片
应用程序可能会使用堆API,.NET垃圾收集器或C运行时malloc库来分配虚拟内存,但是所有这些都依赖于VirtualAlloc API。当应用程序耗尽地址空间时,VirtualAlloc以及因此分层的内存管理器将返回错误(由NULL地址表示)。为了演示各种Windows限制,我为第4版Windows内部版本编写的Testlimit实用程序重复调用VirtualAlloc,直到指定-r开关时出现错误。因此,当您在32位Windows上运行32位版本的Testlimit时,它将占用整个2GB的地址空间:
文章图片
2010 MB不是2GB,但是Testlimit的其他代码和数据,包括它的可执行文件和系统DLL,都是不同的。您可以通过在Process Explorer中查看其虚拟大小来查看其消耗的地址空间总量:
文章图片
一些应用程序(如SQL Server和Active Directory)可以管理大型数据结构,并且可以同时将更多内容加载到其地址空间中,从而实现更好的性能。因此,Windows NT 4 SP3引入了启动选项/ 3GB,通过将系统地址空间的大小减少到1GB,可以提供3GB的4GB地址空间,而Windows XP和Windows Server 2003引入了/ userva选项,在2GB和3GB之间任意分割:
文章图片
然而,要利用2GB行以上的地址空间,进程必须在其可执行映像中设置“可识别大地址空间”标志。访问额外的虚拟内存是选择加入,因为有些应用程序已经假定他们会给地址空间最多2GB。由于引用地址低于2GB的指针的高位始终为零,因此它们将使用指针中的高位作为自己数据的标志,并在引用数据之前将其清除。如果他们运行一个3GB的地址空间,他们会无意中截断值大于2GB的指针,导致程序错误,包括可能的数据损坏。
Windows中的所有Microsoft服务器产品和数据密集型可执行文件均标有大地址空间感知标志,包括Chkdsk.exe,Lsass.exe(在域控制器上承载Active Directory服务),Smss.exe(会话管理器)以及Esentutl.exe(Active Directory Jet数据库修复工具)。您可以看到图像是否带有Visual Studio自带的Dumpbin实用程序的标志:
文章图片
Testlimit也被标记为可以识别大地址,所以如果用3GB的用户地址空间启动时用-r开关运行它,你会看到如下所示:
文章图片
由于64位Windows上的地址空间远远大于4GB,我将稍后介绍,Windows可以为32位进程提供最多4GB的地址空间,并将剩下的空间用于操作系统的虚拟内存。如果您在64位Windows上运行Testlimit,则会看到它占用整个32位可寻址地址空间:
文章图片
64位进程使用64位指针,所以它们的理论最大地址空间是16艾字节(2 ^ 64)。但是,Windows不会在活动进程和系统之间平均分配地址空间,而是在进程的地址空间中定义一个区域,为系统内存资源(如系统页表项(PTE)),文件缓存以及分页和非分页池。
进程地址空间的大小在IA64和x64版本的Windows上是不同的,通过平衡哪些应用程序需要的内存开销(页表页面和转换后备缓冲区 - TLB - 项目)来支持地址空间。在x64上,这是8192GB(8TB),在IA64上是7168GB(7TB - 与x64的1TB差距来自于IA64顶层页面目录为Wow64映射保留插槽的事实)。在Windows的IA64和x64版本上,各种资源地址空间区域的大小为128GB(例如,非页面缓冲池分配有128GB的地址空间),除了分配1TB的文件缓存外。因此,64位进程的地址空间看起来像这样:
文章图片
这个数字并不是按比例绘制的,因为即使是8TB,更小的128GB,也不会是一条小条子。只要说像我们的宇宙那样,在64位进程的地址空间中就有很多空虚。
当您使用-r开关在64位Windows上运行64位版本的Testlimit(Testlimit64)时,您将看到它消耗8TB,这是它可以管理的地址空间部分的大小:
文章图片
文章图片
承诺的内存
Testlimit的-r开关有保留虚拟内存,但实际上没有提交。保留的虚拟内存不能实际存储数据或代码,但应用程序有时使用保留来创建大块虚拟内存,然后根据需要提交,以确保提交的内存在地址空间中连续。当一个进程提交一个虚拟内存区域时,操作系统保证它可以将进程存储在内存中的所有数据保存在物理内存或磁盘上。这意味着一个进程可能会遇到另一个限制:提交限制。
正如您对提交保证的描述所期望的那样,提交限制是物理内存和分页文件大小的总和。实际上,由于操作系统为了自己的使用而保留物理内存的一部分,所以并不是所有的物理内存都会占用这个提交限制。所有活动进程的已提交虚拟内存量(称为当前提交费用)不能超过系统提交限制。达到提交限制时,提交内存的虚拟分配失败。这意味着即使是一个标准的32位进程也可能会在虚拟内存分配失败之前达到2GB的地址空间限制。
当前的提交费用和提交限制由Process Explorer在Commit Charge部分的System Information窗口中和Commit History条形图和图表中进行跟踪:
文章图片
文章图片
在Vista和Windows Server 2008之前的任务管理器显示了类似的当前提交费用和限制,但在其图中调用当前提交费用“PF Usage”:
文章图片
在Vista和Server 2008上,任务管理器不显示提交费用图,并使用“页面文件”标记当前提交费用和限制值(尽管即使没有分页文件,它们也将是非零值) :
文章图片
您可以通过使用-m开关运行Testlimit来强调提交限制,它指示它分配提交的内存。Testlimit的32位版本在达到提交限制之前可能达到也可能不达到其地址空间限制,具体取决于物理内存的大小,分页文件的大小以及运行时的当前提交费用。如果您正在运行32位Windows,并希望看到系统在达到提交限制时的行为,只需运行Testlimit的多个实例,直到达到提交限制,然后再耗尽其地址空间。
请注意,默认情况下,页面文件被配置为增长,这意味着当提交费用接近它时,提交限制将会增长。即使分页文件达到最大尺寸时,Windows仍然保留一些内存,其内部调整以及缓存数据的应用程序可能会释放更多内存。Testlimit预期这一点,当它达到提交限制时,它会休眠几秒钟,然后尝试分配更多的内存,无限期地重复,直到你终止它。
如果运行64位版本的Testlimit,几乎可以确定在耗尽地址空间之前会达到提交限制,除非物理内存和分页文件总和超过8TB(如前所述,这是64位版本的大小) bit应用程序可访问的地址空间。以下是在我的8GB系统上运行的64位Testlimit的部分输出(我指定了100MB的分配大小以使其更快地泄漏):
文章图片
以下是Testlimit暂停后允许分页文件增长的步骤提交历史记录图:
文章图片
当系统虚拟内存不足时,应用程序可能会失败,尝试执行例行操作时可能会遇到奇怪的错误消息。但是在大多数情况下,Windows将能够为您呈现低内存分辨率对话框,就像我在运行此测试时所做的那样:
文章图片
退出Testlimit后,当内存管理器截断它创建的分页文件的尾部以适应Testlimit的极端提交请求时,提交限制可能会再次下降。在这里,Process Explorer显示当前限制远低于Testlimit运行时达到的峰值:
文章图片
处理提交的内存
由于提交限制是一个全局资源,其消耗可能导致性能下降,应用程序故障甚至系统故障,所以一个自然的问题是“提交的代价是多少”。要准确回答这个问题,您需要了解应用程序可以分配的不同类型的虚拟内存。
并非所有进程分配的虚拟内存都计入提交限制。如你所见,保留的虚拟内存不会。在磁盘上表示文件的虚拟内存称为文件映射视图,除非应用程序要求写入时复制语义,否则也不会计入限制,因为Windows可以放弃与物理内存中与视图关联的任何数据,然后从文件中检索它。Testlimit的地址空间中映射其可执行文件和系统DLL映像的虚拟内存因此不计入提交限制。有两种类型的进程虚拟内存可以计入提交限制:private和pagefile-backed。
私有虚拟内存是垃圾收集器堆,本地堆和语言分配器的基础。它被称为私有的,因为根据定义,它不能在进程间共享。出于这个原因,很容易归因于一个进程,而Windows使用Private Bytes性能计数器跟踪它的使用情况。Process Explorer在“进程属性”对话框的“性能”页面的“虚拟内存”部分的“专用字节”列中显示进程专用字节的使用情况,并以图形形式显示在进程属性对话框的“性能图表”页面上。这是Testlimit64达到提交限制时的样子:
文章图片
文章图片
页面文件支持的虚拟内存很难归类,因为它可以在进程之间共享。事实上,没有特定于流程的计数器,您可以查看流程分配或引用的数量。当你用-s开关运行Testlimit时,它会分配页面文件支持的虚拟内存,直到达到提交限制,但是即使在超过29GB的提交之后,进程的虚拟内存统计信息也不会提供任何指示负责:
文章图片
出于这个原因,我在前面添加了-l开关。进程必须打开一个页面文件支持的虚拟内存对象(称为段),以便在其地址空间中创建页面文件支持的虚拟内存的映射。尽管Windows保留了现有的虚拟内存,即使应用程序关闭了由它创建的部分的句柄,大多数应用程序仍然保持句柄处于打开状态。-l开关打印进程已打开的页面文件支持部分的分配大小。以下是Testlimit在使用-s开关运行后打开的句柄的部分输出:
文章图片
你可以看到Testlimit在1MB的块中分配了页面文件支持的内存,如果你总结了所有打开的部分的大小,你会发现至少有一个进程贡献了大量的费用。
我应该做多大的分页文件?
也许与虚拟内存相关的最常见的问题之一是,我应该使页面文件有多大?网络上和报刊杂志上都没有可笑的建议,甚至微软也发布了误导性的建议。几乎所有的建议都是基于将RAM大小乘以一定的因子,通用值为1.2,1.5和2.现在您已经理解了分页文件在定义系统的提交限制以及进程如何对提交计费作出贡献的过程中所起的作用,你已经准备好了解这些公式是多么的无用了。
由于提交限制设置了可以通过运行进程同时分配多少私有文件和页面文件支持的虚拟内存的上限,因此合理调整页面文件大小的唯一方法是知道您喜欢的程序的最大总交付费用同时运行。如果提交限制小于该数字,则程序将无法分配所需的虚拟内存,并且无法正常运行。
那么您如何知道您的工作负载需要多少费用?您可能已经注意到在屏幕截图中,Windows跟踪该号码,Process Explorer显示它:峰值提交费用。为了最佳地调整分页文件的大小,您应该启动所有同时运行的应用程序,加载典型数据集,然后记下提交电荷峰值(或者在知道最大负载的一段时间后查看此值) 。将页面文件的最小值设置为该值减去系统中RAM的数量(如果该值为负值,则选择最小大小以允许配置的崩溃转储类型)。如果您希望有一些潜在的大型提交需求的呼吸空间,请将该数字设置为最大值的两倍。
有些人觉得没有分页文件导致更好的性能,但一般来说,有一个分页文件意味着Windows可以写修改列表中的页面(代表那些没有被主动访问,但没有被保存到磁盘的页面)分页文件,从而使该内存可用于更有用的目的(进程或文件缓存)。因此,虽然可能有一些工作负载在没有分页文件的情况下执行得更好,但一般来说,这意味着更多的可用内存可用于系统(不必介意,Windows将无法编写内核崩溃转储,而无需分页文件大小足以容纳他们)。
分页文件配置是在系统属性,您可以通过在运行对话框中键入“sysdm.cpl”,单击高级选项卡,单击性能选项按钮,单击高级选项卡(这是真正的高级) ,然后点击更改按钮:
文章图片
您会注意到,默认配置是为Windows自动管理页面文件大小。当在Windows XP和Server 2003上设置该选项时,Windows将创建一个页面文件,如果RAM小于1GB,则该文件的最小大小是RAM的1.5倍; 如果大于1GB,则RAM大小是RAM的三倍。在Windows Vista和Server 2008上,最小值应该足够大以容纳内核内存崩溃转储,并且是RAM加上300MB或1GB,以较大者为准。最大值是RAM大小的三倍或4GB,以较大者为准。这就解释了为什么我的8GB 64位系统的峰值提交在其中一个屏幕截图中显示的是32GB。我猜那些编写代码的人从我提到的其中一本杂志上得到了他们的指导!
与虚拟内存相关的几个最终限制是Windows支持的页面文件的最大大小和数量。32位Windows的最大页面文件大小为16TB(如果由于某种原因以非PAE模式运行,则为4GB),而64位Windows可以在x64上具有高达16TB的页面文件,IA64上的页面大小为32TB。Windows 8 ARM的最大分页文件大小是4GB。对于所有版本,Windows最多支持16个分页文件,每个文件必须位于单独的卷上。
版 |
限制x86不带PAE |
限制x86 w / PAE |
限制在ARM上 |
限制在x64 |
限制IA64 |
Windows 7的 |
4GB |
16 TB |
16 TB |
||
Windows 8 |
16 TB |
4GB |
16 TB |
||
Windows Server 2008 R2 |
16 TB |
32 TB |
|||
Windows Server 2012 |
【C/C++|推动Windows的限制(虚拟内存)】16 TB |
推荐阅读
- opencv|opencv C++模板匹配的简单实现
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- c++基础概念笔记
- 我用我的坚持来推动读写
- 推动NFT走出监管困境,BSN推出支持NFT基础设施网络
- Caffe在Windows10下CPU版本的安装(cpu+anaconda3+vs2013+pycaffe)
- 牛逼!C++开发的穿越丛林真人游戏,游戏未上线就有百万人气
- 笔记|如何在Windows11安装安卓子系统()
- windows11|Windows11安装Android子系统
- Windows10|Windows10,Version,1903,7月更新,MSDN镜像下载