你应该分配多少内存?

时间:2009-06-23 17:39:56

标签: c++ new-operator dynamic-memory-allocation

背景:我正在编写一个使用大量地理数据的C ++程序,并且希望一次性加载大块进程。我不得不使用为32位机器编译的应用程序。我正在测试的机器运行的是64位操作系统(Windows 7),并且有6 GB的内存。使用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千兆字节限制。但是,当nBandBytes为466,560,000时,第二次尝试新抛出std :: bad_alloc。在这个阶段,进程的工作集(内存)值是665,232 K所以,我似乎无法获得分配的内存。

有人提到32位Windows应用程序的2 gig限制,使用win32的/ 3GB开关可以扩展到3 gig。在这种环境下这是一个很好的建议,但与这种情况无关。

在具有32位应用程序的64位操作系统下,您应该分配多少内存?

8 个答案:

答案 0 :(得分:11)

操作系统想要给你。默认情况下,Windows允许32位进程具有2GB的地址空间。这被分成几个块。为堆栈预留一个区域,为每个可执行文件和加载的dll分配一个区域。无论剩下什么都可以动态分配,但不能保证它将是一个大的连续块。它可能是几个较小的块,每块几百MB。

如果使用LargeAddressAware标志进行编译,64位Windows将允许您使用完整的4GB地址空间,这应该有所帮助,但一般来说,

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

答案 1 :(得分:6)

在Windows 32位上,正常进程最多可以占用2 GB,但使用/3GB切换时,它可以达到3 GB(对于Windows 2003)。

但在你的情况下,我认为你正在分配连续的内存,所以发生了异常。

答案 2 :(得分:4)

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

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

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

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

如果你真的了解内存管理在Windows中的运作方式,请阅读this article

答案 3 :(得分:2)

在ElephantsDream项目期间,Blender Foundation与Blender 3D有类似的问题(尽管在Mac上)。不能包含链接但谷歌:blender3d内存分配问题,它将是第一项。

解决方案涉及文件映射。我自己没试过,但你可以在这里阅读:http://msdn.microsoft.com/en-us/library/aa366556(VS.85).aspx

答案 4 :(得分:1)

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

如果要在64位操作系统上分配千兆字节的内存,请使用64位进程。

答案 5 :(得分:1)

您应该能够为每个进程分配大约2GB的空间。 This article(PDF)解释详情。但是,您可能无法获得一个甚至接近那么大的连续块。

答案 6 :(得分:1)

即使您分配较小的块,也无法获得所需的内存,特别是如果周围的程序具有不可预测的内存行为,或者您需要在不同的操作系统上运行。根据我的经验,32位进程的堆空间大约为1.2GB。

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

答案 7 :(得分:1)

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

正如其他人所建议的那样,避免极大的连续分配可能是最好的。

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