2009-06-23 97 views
7

背景:我正在写一个C++程序,处理大量的地理数据,并希望加载大块进行一次处理。我受限于使用为32位机器编译的应用程序。我正在测试的机器运行的是64位操作系统(Windows 7),并具有6个RAM。使用MS VS 2008你应该能够分配多少内存?

我有以下代码:

byte* pTempBuffer2[3]; 
try 
{ 
    //size_t nBufSize = nBandBytes*m_nBandCount; 
    pTempBuffer2[0] = new byte[nBandBytes]; 
    pTempBuffer2[1] = new byte[nBandBytes]; 
    pTempBuffer2[2] = new byte[nBandBytes]; 
} 
catch (std::bad_alloc) 
{ 
    // If we didn't get the memory just don't buffer and we will get data one 
    // piece at a time. 
    return; 
} 

我希望我能够分配内存,直到应用达到32位寻址的4 GB的限制。但是,当nBandBytes为466,560,000时,新的第二次尝试会抛出std :: bad_alloc。在这个阶段,进程的工作集(内存)值是665,232 K因此,我似乎无法获得分配的内存。

已经有一个2演出限制在32位Windows应用程序,其可以扩展到3演出和/ 3GB开关为Win32一些提。这是在这种环境下的好建议,但与这种情况无关。

多少内存你应该能够在64位操作系统下的分配与32位应用程序?

+0

我在网上发现了这个参考资料:“如果你在64位操作系统上作为32位应用运行,那么你可以获得所有的4G地址空间,所有这些都可以由物理内存支持(如果你有RAM),即使没有你自己使用64位指针。“从博客:http://blogs.msdn.com/ricom/archive/2009/06/10/visual-studio-why-is-there-no-64-bit-version。aspx – Bill 2009-06-23 18:10:11

+0

在我的32位机器上,我可以在简单测试中分配466,560,000×3个字节。似乎是在你的情况下分配点处已经分散的进程内存。 – 2009-06-23 18:19:21

+1

我很难选择一个答案来标记正确的这个问题。我相信答案很复杂,取决于很多因素。内存映射文件是一个很好的答案,但这个问题的根本原因似乎是内存碎片。 bke1指出了用于查看内存的好工具,许多人谈论内存碎片,但我选择了第一个明确指出问题并给出了严格限制的答案(64位下的4 GB和右侧标记)。 – Bill 2009-06-23 19:16:50

回答

10

尽可能多的OS想给你。默认情况下,Windows允许32位进程拥有2GB的地址空间。这分成几块。为堆栈预留一个区域,为每个可执行文件和dll加载其他区域。剩下的东西可以动态分配,但不能保证它会成为一个大的连续块。它可能是几个几百MB的小块。

如果与LARGEADDRESSAWARE标志进行编译,64位的Windows将让您使用完整的4GB地址空间,这应该有点帮助,但总的来说,

  • 你不应该假设可用内存是连续的。您应该可以使用多个较小的分配而不是几个较大的分配,并且
  • 如果需要大量内存,则应该将其编译为64位应用程序。
6

在Windows 32位,正常过程可能需要2 GB最大,但与/3GB开关它可达到3 GB(适用于Windows 2003)。

但在你的情况下,我认为你是分配连续的内存,所以出现异常。

1

在nBandBytes为466,560,000时,您试图分配1.4 GB。 32位应用程序通常只能访问2 GB内存(如果使用/ 3GB引导并且可执行文件标记为可识别大地址空间,则应用程序更多)。你可能很难为你的大块内存找到许多连续地址空间块。

如果你想在64位操作系统分配的内存千兆字节,使用一个64位的过程。

1

您应该能够为每个进程分配总共大约2GB的内存。 This article(PDF)解释了详细信息。但是,您可能无法获得一个甚至接近这个大的连续块。

1

即使你在较小的块分配,你不能得到你所需要的内存,尤其是如果周围的程序有不可预知的记忆行为,或者如果您需要在不同的操作系统上运行。根据我的经验,32位处理器上的堆空间大约为1.2GB。

在这个内存量,我会建议手动写入磁盘。将您的阵列封装在管理内存的类中,并在必要时写入临时文件。希望您的程序的特点是,您可以有效地缓存部分数据,而不会过多地访问磁盘。

4

您可以分配尽可能多的内存,因为您的页面文件可以让您 - 即使没有/ 3GB开关,您也可以毫不费力地分配4GB内存。

阅读this article了解如何思考物理内存,虚拟内存和地址空间(这三者是不同的东西)。简而言之,您拥有与RAM相同的物理内存,但您的应用程序实际上完全没有与该物理内存的交互 - 它只是将数据存储在虚拟内存中的便利之处。您的虚拟内存受到页面文件大小的限制,您的应用程序可以使用的数量受到其他应用程序使用量的限制(尽管您可以分配更多,但实际上并未使用它)。你在32位世界中的地址空间是4GB。其中,2 GB分配给内核(如果使用/ 3BG开关,则为1 GB)。在剩下的2GB中,有一些将被堆栈用完,一些则由您正在运行的程序(以及所有的dll等)耗尽。它会变得分散,而且你只能获得如此多的连续空间 - 这是你的分配失败的地方。但是由于该地址空间只是访问为您分配的虚拟内存的一种便捷方式,因此可以分配更多的内存,并且一次将几块内存分配到您的地址空间中。

Raymond Chen has an example如何分配4GB内存并将其部分映射到您的地址空间的一部分。

在32位Windows,最大可分配为16TB和256TB在64位的Windows。

如果您真的了解内存管理在Windows中的工作原理,请参阅this article

2

在ElephantsDream项目Blender基金会与搅拌机3D过类似的问题(尽管在Mac)。不能包含链接,但谷歌:blender3d内存分配问题,它将成为第一项。

该解决方案涉及文件映射。还没有尝试过,但你可以在这里看到它:http://msdn.microsoft.com/en-us/library/aa366556(VS.85).aspx

1

Sysinternals VMMap非常适合研究虚拟地址空间碎片,这可能会限制你可以分配多少连续的内存。我建议将其设置为显示可用空间,然后按大小进行排序以查找最大空闲区域,然后按地址进行排序以查看将最大空闲区域(可能是已重新绑定的DLL,共享内存区域或其他堆)分开的内容。

避免非常大的连续分配是可能是最好的,正如其他人建议。

设置LARGE_ADDRESS_AWARE=YES(如jalf建议)是很好的,只要你的应用程序依赖的库与它兼容即可。如果这样做,则应该使用AllocationPreference注册表项集测试代码,以启用自顶向下虚拟地址分配。