4

当虚拟大小达到大约 2GB(32 位应用程序,启用大地址感知)时,我正在使用 Windows 上的 C++ 构建的服务器应用程序内存不足。但是,我注意到 Private Bytes 要小得多。目前的统计数据是:

虚拟大小:2.6GB 私有字节:1.6GB

这两个数字的差异是 1GB。所以我的问题是:

  1. 这个 1GB 的差异代表什么?
  2. 我的应用程序是否由于虚拟大小或私有字节而耗尽内存?

我还通过 VMMap 实用程序运行了我的应用程序,我注意到“私有数据”通常比提交的大小高一个数量级。换句话说,私有数据的总大小可能是 200MB,但提交的大小只有 20MB。我不太确定私有数据是什么,但根据我目前的研究,它似乎表明它只是堆的一部分。

编辑:

我已经使用 Purify 寻找内存泄漏,但我并没有真正找到任何有用的东西。没有指针的内存形式的内存泄漏似乎不是问题,但是内存被占用太久的内存泄漏可能是一个问题,我还没有研究过。但是,关键是要了解虚拟大小导致内存不足问题的原因。问题 #1 对我来说是理解这一点最重要的。

4

4 回答 4

6

这需要一点解释,所以请在这里坚持。

首先,这个话题是一个令人困惑的矛盾术语的泥潭,所以请抛弃你对“虚拟内存”与磁盘有关的所有概念。

  • 物理内存是存储在物理设备上的内存。这通常是指系统 RAM,但也可以是磁盘缓冲区、网卡缓冲区、显卡 VRAM 等。
  • 虚拟内存是一组映射到用户模式(虚拟)地址范围的物理地址范围,以便可以以安全和分隔的方式访问内存。

关于我们为什么这样做的快速说明:如果我们给进程直接内存地址,我们只能(可能)有一个内存存储。这很不方便并且不利于性能。当虚拟地址转换为系统内存 (RAM) 范围之外的物理地址时,处理器会发出页面错误。这向操作系统中的中断处理程序发出信号,然后可以将内存访问操作委托给不同的设备。有用!

在 32 位 Windows 系统上,进程在任一时间点可以寻址的最大虚拟内存量为 2GB。这可以使用 AWE 增加到 3GB,或者使用 AWE 增加到 4GB /4GT。这并不意味着一个进程只能分配 2GB(或 3GB / 4GB,取决于前面讨论的设置)的内存。这只是意味着它不能同时访问更多内容。

例如,如果您打开一个 1GB 大小的内存映射文件,您的虚拟内存使用量将增加 1GB。您没有触及 RAM,也没有触及磁盘,但您已经为您的进程分配了一块虚拟地址空间。如果您想在此内存映射文件可用的同时分配 1.1GB 的 RAM,则不能。您必须首先从您的进程中取消映射文件。请记住,内存仍然可以保持分配状态并充满数据,但实际上并未映射到您的进程中。如果您的机器上有 8GB 的​​ RAM,您可以用数据填充其中的 6GB,并将其中的 2GB 映射到您的进程中。当您需要使用该内存的不同部分时,您必须取消映射现有块并映射其他部分。

因此,关于您所看到的差异:

  1. Private bytes 告诉您进程映射了多少字节的虚拟设备内存,不包括与其他进程共享的虚拟内存(例如映射文件、全局堆等)。

  2. 工作集告诉你你正在使用多少字节的物理内存。这包括物理内存、设备缓冲区和映射文件。这是一个非常奇怪的数字,因为它等同于触摸的物理内存 + 映射的虚拟非系统内存。一般来说,你应该完全忽略这个数字。它实际上对调试内存泄漏毫无用处。

  3. 虚拟字节是您已映射的虚拟内存总量。

不同之处在于您已将共享虚拟内存(例如一堆 DLL 文件或一块全局堆)映射到您的进程中。差异表明这些共享映射的总大小大约为 1GB。

请记住,这些都与交换无关,交换是将系统内存页面传输到磁盘(所谓的“页面文件”)以增加快速系统资源 (RAM) 的可用性。该文件的命名在 Windows 的这一领域造成了无穷无尽的混乱,当微软最终决定将其称为“交换”而不是“虚拟内存”或“页面文件”时,我会很高兴。

于 2012-07-02T15:45:24.787 回答
2
  1. Virtual Size vs Private Bytes 解释:什么是私有字节、虚拟字节、工作集?(见下面的报价)
  2. 您的应用程序可能会达到 2 GB 的虚拟大小限制,尤其是。因为您自己也看到了这种行为
  3. /LARGEADDRESSAWARE仅当系统本身在启用/3GB AKA 4GTWin32的情况下启动时,才扩展操作系统中应用程序的虚拟大小限制

Virtual Bytes 是整个进程占用的总虚拟地址空间。这就像工作集,从某种意义上说,它包括内存映射文件(共享 DLL),但它还包括备用列表中的数据和已经被分页并位于磁盘某处的页面文件中的数据。在重负载下,系统上每个进程使用的总虚拟字节数加起来会比机器实际拥有的内存多得多。

所以关系是:

  • Private Bytes 是您的应用实际分配的,但包括页面文件的使用;
  • 工作集是非分页私有字节加上内存映射文件;
  • 虚拟字节是工作集加上分页的私有字节和备用列表。
于 2012-07-02T15:31:35.247 回答
1

我在我的机器上遇到了类似的问题,其中 C/C++/.NET win32 应用程序内存不足。它消耗了所有 2GB 的虚拟地址。它看起来像虚拟地址耗尽,因为 Process Explorer 显示应用程序只占用了大约 900MB 内存。VMMap 显示了 1.6GB 的私有数据和大约 700MB 的未提交内存。

原因很简单。配置为测试应用程序的应用程序验证程序 (C:\Windows\SysWOW64\appverif.exe)(标记为基本测试 - vfbasics.dll)。从应用程序验证器中删除应用程序后,它工作正常。

于 2014-11-07T16:07:17.953 回答
0

只是一个评论:启用大地址感知仅向操作系统发出信号,它可以安全地划分进程的虚拟地址空间,从该特定可执行文件创建,以 3:1 方式而不是通常的 2:2 方式。应用程序应该明确指出它支持 3:1 除法的原因有很多,但最明显的一个原因是在 2:2 模式下,可以使用探测虚拟地址的 MSB 来测试该地址是否属于内核部分的虚拟地址空间或用户部分。在 3:1 中,该测试不再有效,因为 MSB 也是1占虚拟地址空间用户部分的 1/3。这要求该应用程序可能调用的驱动程序也应该知道可能的 3:1 除法,并且应该使用另一种方法来测试给定的虚拟地址是否属于非用户空间。

正如 Roman R. 所指出的,您仍然必须明确告诉内核启用对 3:1 VA 空间划分的支持。

于 2012-07-02T15:49:21.203 回答