虚拟大小导致程序内存不足
Posted
技术标签:
【中文标题】虚拟大小导致程序内存不足【英文标题】:Virtual Size causing program to run out of memory 【发布时间】:2012-07-03 00:58:49 【问题描述】:当虚拟大小达到大约 2GB(32 位应用程序,启用大地址感知)时,我正在使用 Windows 上的 C++ 构建的服务器应用程序内存不足。但是,我注意到 Private Bytes 要小得多。目前的统计数据是:
虚拟大小:2.6GB 私有字节:1.6GB
这两个数字相差 1GB。所以我的问题是:
-
这 1GB 的差异代表什么?
我的应用程序是否因虚拟大小或私有字节而耗尽内存?
我还通过 VMMap 实用程序运行了我的应用程序,我注意到“私有数据”通常比提交的大小高一个数量级。换句话说,私有数据的总大小可能是 200MB,但提交的大小只有 20MB。我不太确定私有数据是什么,但根据我目前的研究,它似乎表明它只是堆的一部分。
编辑:
我已经使用 Purify 寻找内存泄漏,但我并没有真正找到任何有用的东西。没有指针的内存形式的内存泄漏似乎不是问题,但是内存被占用太久的内存泄漏可能是一个问题,我还没有研究过。但是,关键是要了解虚拟大小导致内存不足问题的原因。问题 #1 对我来说是最重要的理解这一点。
【问题讨论】:
也许您有一个或多个内存泄漏需要修复? Committed = 应用程序实际使用的内存,private = 专为应用程序保留的内存?我猜虚拟大小=磁盘上分页的数据量。我必须实际调查一下才能确定。 @JAB 不正确。我会发布一个解释的答案。 如果您尝试使用用户模式转储堆 (UMDH) 工具,内存使用可能是由于 GFlag 的堆栈跟踪集合;查看 Paul Arnold 对***.com/questions/1831683/…的回复 【参考方案1】:这需要一点解释,所以请在这里坚持。
首先,这个话题是一个由相互冲突的术语组成的令人困惑的泥潭,所以请抛开所有关于“虚拟内存”与磁盘有关的概念。
物理内存是存储在物理设备上的内存。这个通常是指系统RAM,但也可以是磁盘缓冲区、网卡缓冲区、显卡VRAM等。 虚拟内存是一组映射到用户模式(虚拟)地址范围的物理地址范围,以便可以安全和分隔的方式访问内存。简要说明为什么我们这样做:如果我们为进程提供直接内存地址,我们只能(可能)拥有一个内存存储。这很不方便并且不利于性能。当虚拟地址转换为系统内存 (RAM) 范围之外的物理地址时,处理器会发出页面错误。这向操作系统中的中断处理程序发出信号,然后可以将内存访问操作委托给不同的设备。有用!
在 32 位 Windows 系统上,一个进程可以在任何一个时间点寻址的最大虚拟内存量为 2GB。这可以使用 AWE 增加到 3GB,或者使用 /4GT
和 AWE 增加到 4GB。这并不意味着一个进程只能分配 2GB(或 3GB / 4GB,取决于前面讨论的设置)的内存。这只是意味着它不能同时访问更多内容。
例如,如果您打开一个 1GB 大小的内存映射文件,您的虚拟内存使用量将增加 1GB。您没有触及 RAM,也没有触及磁盘,但您已经为您的进程分配了一块虚拟地址空间。如果您想在此内存映射文件可用的同时分配 1.1GB 的 RAM,则不能。您必须首先从您的进程中取消映射文件。请记住,内存仍然可以保持分配状态并充满数据,但实际上并未映射到您的进程中。如果您的机器上有 8GB 的 RAM,您可以用数据填充其中的 6GB,并将其中的 2GB 映射到您的进程中。当您需要使用该内存的不同部分时,您必须取消映射现有块并映射其他部分。
那么,看看你所看到的差异:
私有字节告诉您您的进程已映射了多少字节的虚拟设备内存,不包括与其他进程共享的虚拟内存(例如映射文件、全局堆等)。
工作集告诉您正在使用的物理内存字节数。这包括物理内存、设备缓冲区和映射文件。这是一个非常奇怪的数字,因为它等同于触摸的物理内存 + 映射的虚拟非系统内存。一般来说,你应该完全忽略这个数字。它实际上对调试内存泄漏毫无用处。
Virtual bytes 是您已映射的虚拟内存总量。
不同之处在于您已将共享虚拟内存(例如一堆 DLL 文件或一个全局堆块)映射到您的进程中。差异表明这些共享映射的总大小约为 1GB。
请记住,其中 none 与交换有关,即交换系统内存页面到磁盘(所谓的“页面文件”)以增加快速系统资源 (RAM) 的可用性。该文件的命名在 Windows 的这一领域造成了无穷无尽的混乱,当微软最终决定将其称为“交换”而不是“虚拟内存”或“页面文件”时,我会很高兴。
【讨论】:
哦,肯定读一读:blogs.technet.com/b/markrussinovich/archive/2008/11/17/… Mark Russinovich 是这种低级内存的“大笨蛋”。 “这可以使用 PAE 增加到 3GB”。实际上,PAE 允许 32 位操作系统访问超过 4 GB 的 物理 内存。 AWE 允许 32 位进程使用内存窗口访问超过 2 GB(或 4GT 时为 3 GB)的用户内存。 4GT 允许应用程序在虚拟地址空间的用户部分拥有高达 3 GB 的映射内存。 抱歉,我的术语弄混了。编辑修复。 我想后续的问题是:为什么 dll 会引入如此高的共享内存使用率?【参考方案2】:-
虚拟大小与私有字节的解释:What is private bytes, virtual bytes, working set?(请参阅下面的引用)
您的应用程序可能会达到 2 GB 的虚拟大小限制,尤其是。因为你自己也看到了这种行为
/LARGEADDRESSAWARE
仅当系统本身在启用 /3GB AKA 4GT 的情况下启动时,才会在 Win32
操作系统中扩展应用程序的虚拟大小限制
Virtual Bytes 是被占用的总虚拟地址空间 整个过程。这就像工作集,从某种意义上说,它 包括内存映射文件(共享 DLL),但也包括数据 在备用列表和已经被调出的数据中 坐在磁盘上某处的页面文件中。使用的总虚拟字节数 重负载下系统上的每个进程将加起来 比机器实际拥有的内存要多得多。
所以关系是:
私有字节是您的应用实际分配的,但包括页面文件使用情况; Working Set 是非分页的 Private Bytes 加上内存映射的文件; 虚拟字节是工作集加上分页私有字节和备用列表。
【讨论】:
我已经阅读了您链接的答案的次数比我记得的要多,但我仍然感到困惑。我想具体知道为什么这些数字如此不同,但我什至无法确定这一点,除非我确切知道是什么导致了这种差异。那么它是备用列表和/或磁盘上的页面上的数据吗?如果是这种情况,为什么 Windows 不删除未使用的页面(从而减小虚拟大小)而不仅仅是失败? 对于初学者来说很简单:new
和 malloc
的私有字节数 - 当它们成功时,分配的内存有一个有效的指针,因此它们会占用地址空间。但是,您将所有代码也映射到地址空间,不仅是您的,而且所有这些 API DLL 也都映射到了地址空间,它们都有自己的地址。而且它们不是私有字节。因此,如果您打开 Process Explorer 或 Visual Studio 的“模块”窗格 - 您将看到有多少模块已加载到流程中,并且它们都计入您询问的差异。【参考方案3】:
我的机器上有类似的问题,C/C++/.NET win32 应用程序内存不足。它消耗了所有 2GB 的虚拟地址。它看起来像虚拟地址耗尽,因为 Process Explorer 显示应用程序仅占用了大约 900MB 内存。 VMMap 显示了 1.6GB 的私有数据和大约 700MB 未提交的内存。
原因很简单。配置为测试应用程序的应用程序验证程序 (C:\Windows\SysWOW64\appverif.exe)(标记为基本测试 - vfbasics.dll)。从应用程序验证程序中删除应用程序后,它工作正常。
【讨论】:
我遇到了同样的问题。为了继续使用应用程序验证程序,我发现将 appverif.exe 从 Full Page Heap-mode 切换到纯 Normal Page Heap-mode 会恢复被监视进程的内存使用情况正常。 Full-mode 和 Normal-mode 之间的切换是通过在 Application Verifier>Tests>Basics>Heap>Right- 中切换 Full-checkbox 来完成的单击菜单>属性。或者将 Windows 注册表 PageHeapFlags 字符串值设置为 Normal-mode 的 0x2。 0x3 是全模式。 appverif.exe>Help>Heaps Stop Details>Heap details说Normal强制崩溃直到free()。【参考方案4】:只是评论:启用大地址感知仅向操作系统发出信号,它可以安全地划分进程的虚拟地址空间,从该特定可执行文件创建,以 3:1 方式而不是通常的 2:2 方式。应用程序应该明确指出它支持 3:1 除法的原因有很多,但最明显的一个原因是在 2:2 模式下,可以使用探测虚拟地址的 MSB 来测试该地址是否属于内核部分的虚拟地址空间或用户部分。在 3:1 中,该测试不再有效,因为 MSB 也是 1
,占虚拟地址空间用户部分的 1/3。这要求该应用程序可能调用的驱动程序也应该知道可能的 3:1 除法,并且应该使用另一种方法来测试给定的虚拟地址是否属于非用户空间。
正如 Roman R. 所指出的,您仍然必须明确告诉内核启用对 3:1 VA 空间划分的支持。
【讨论】:
请记住,/3GB 会在 RAM 不多的大屏幕分辨率上导致剪贴板出现问题。打印屏幕不适合内核的剪贴板缓冲区,因此操作失败。奇怪!以上是关于虚拟大小导致程序内存不足的主要内容,如果未能解决你的问题,请参考以下文章
虚拟内存是啥东西?有啥用?如果虚拟内存不足会有啥危害?如何调整虚拟内存的大小?