虚拟大小导致程序内存不足

时间:2012-07-02 15:25:06

标签: c++ windows memory

我正在使用C ++在Windows上构建的服务器应用程序在虚拟大小达到大约2GB(32位应用程序,启用了大地址识别)时会耗尽内存。但是,我注意到Private Bytes明显更小。目前的统计数据是:

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

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

  1. 这1GB差异代表什么?
  2. 由于虚拟大小或私有字节,我的应用程序是否内存不足?
  3. 我还通过VMMap实用程序运行我的应用程序,我注意到“私有数据”通常比承诺大小高出一个数量级。换句话说,私有数据的总大小可能是200MB,但承诺大小只有20MB。我不确定私有数据是什么,但根据我的研究到目前为止它似乎表明它只是堆的一部分。

    编辑:

    我使用Purify查找了内存泄漏但我没有找到任何有用的东西。没有指针的内存形式的内存泄漏似乎不是问题,但内存泄漏持续时间太久可能是一个问题,我还没有考虑过。但是,关键是要了解Virtual Size导致内存不足问题的原因。问题#1对我来说是最重要的。

4 个答案:

答案 0 :(得分:6)

这需要一点解释,所以请坚持下去。

首先,这个主题是一个令人困惑的冲突条款的泥潭,所以请抛弃你所拥有的“虚拟内存”与磁盘有关的所有概念。

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

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

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

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

所以,看看你所看到的差异:

  1. 专用字节告诉您进程已映射的虚拟设备内存的字节数,不包括与其他进程共享的虚拟内存(例如映射文件,全局堆等)。

  2. 工作集会告诉您正在使用的物理内存的字节数。这包括物理内存,设备缓冲区和映射文件。这是一个非常奇怪的数字,因为它等同于触及的物理内存+映射的虚拟非系统内存。一般来说,你应该完全忽略这个数字。调试内存泄漏几乎没用。

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

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

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

答案 1 :(得分:2)

  1. 虚拟大小与私人字节说明:What is private bytes, virtual bytes, working set?(见下面的引用)
  2. 您的应用程序可能会达到2 GB的虚拟大小限制,尤其是既然你自己看到了这种行为
  3. /LARGEADDRESSAWARE仅在系统本身启用/3GB AKA 4GT时启动,才会在Win32操作系统中扩展应用程序的虚拟大小限制
  4.   

    虚拟字节数是指占用的虚拟地址空间总量   整个过程。从某种意义上说,这就像工作集一样   包括内存映射文件(共享DLL),但它也包括数据   在待机列表和已经被分页的数据中   坐在磁盘上的某个页面文件中。使用的总虚拟字节数   通过重负载系统上的每个进程将加起来   比机器实际拥有的内存大得多。

         

    所以关系是:

         
        
    • 私有字节是您的应用实际分配的内容,但包含页面文件用法;
    •   
    • Working Set是非分页私有字节加内存映射文件;
    •   
    • 虚拟字节是工作集加分页的专用字节和备用列表。
    •   

答案 2 :(得分:1)

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

原因不仅仅是简单。应用程序验证程序(C:\ Windows \ SysWOW64 \ appverif.exe)配置为测试应用程序(基础测试已标记--vfbasics.dll)。从Application Verifier中删除应用程序后,它工作正常。

答案 3 :(得分:0)

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

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