为什么600MB后动态内存分配失败?

时间:2012-04-28 17:01:57

标签: c++ dynamic-arrays bitarray bad-alloc

我使用三维char数组实现了一个bloom过滤器(位表),它运行良好,直到达到无法再分配内存并提供 bad_alloc 消息的程度。在分配600MB后,它在下一个扩展请求中给出了这个错误。

布隆过滤器(阵列)预计会增长到8到10GB。

这是我用来分配(扩展)位表的代码。

unsigned char ***bit_table_=0;
unsigned int ROWS_old=5;
unsigned int EXPND_SIZE=5;


void expand_bit_table()
     {
         FILE *temp;
         temp=fopen("chunk_temp","w+b");
         //copy old content
         for(int i=0;i<ROWS_old;++i)
             for(int j=0;j<ROWS;++j)
                 fwrite(bit_table_[i][j],COLUMNS,1,temp);
         fclose(temp);
         //delete old table
         chunk_delete_bit_table();
         //create expanded bit table ==> add EXP_SIZE more rows
         bit_table_=new unsigned char**[ROWS_old+EXPND_SIZE];
         for(int i=0;i<ROWS_old+EXPND_SIZE;++i)
            {
                bit_table_[i]=new unsigned char*[ROWS];
                for(int k=0;k<ROWS;++k)
                    bit_table_[i][k]=new unsigned char[COLUMNS];
            }
         //copy back old content

          temp=fopen("chunk_temp","r+b");
         for(int i=0;i<ROWS_old;++i)
         {
            fread(bit_table_[i],COLUMNS*ROWS,1,temp);
         }
          fclose(temp);
         //set remaining content of bit_table_to 0
         for(int i=ROWS_old;i<ROWS_old+EXPND_SIZE;++i)
             for(int j=0;j<ROWS;++j)
                 for(int k=0;k<COLUMNS;++k)
                     bit_table_[i][j][k]=0;

         ROWS_old+=EXPND_SIZE;
     }

数组的最大允许大小是多少,如果这不是问题,我该怎么办呢。

编辑: 它是使用32位平台开发的。

它运行在64位平台(服务器)上,内存为8GB。

3 个答案:

答案 0 :(得分:5)

32位程序必须从虚拟内存地址空间分配内存。其中存储了大量代码和数据,内存是从它们之间的漏洞中分配的。是的,你可以希望的最大值是大约650兆字节,这是最大的可用漏洞。从那里开始迅速下降。您可以通过使数据结构更加智能化来解决它,例如树或列表而不是一个巨大的数组。

您可以使用SysInternals的VMMap实用程序更深入地了解流程的虚拟内存映射。您可能能够更改DLL的基址,使其不会在地址空间的空区域中间垂直。然而,你将获得超过650 MB的可能性很小。

在64位操作系统上有更多的喘息空间,32位进程具有4 GB的地址空间,因为操作系统组件以64位模式运行。您必须使用/ LARGEADDRESSAWARE链接器选项才能允许进程使用它。尽管如此,这只适用于64位操作系统,您的程序仍然可能在32位操作系统上爆炸。当你真的需要那么多虚拟机时,最简单的方法就是将64位操作系统作为先决条件,并构建针对x64的程序。

答案 1 :(得分:1)

32位进程可以访问的最大内存数据理论上是4GB(实际上它会稍微小一些)。因此,您不能同时在内存中拥有10GB数据(即使操作系统支持更多)。此外,即使您动态分配内存,可用的免费存储也会受到堆栈大小的限制。

进程可用的实际内存取决于生成可执行文件的编译器设置。

如果确实需要那么多,请考虑在文件系统中保留(部分)数据。

答案 2 :(得分:1)

32位机器为您提供4GB的地址空间。

操作系统保留了部分内容(默认情况下在Windows上有一半,给你自己2GB。我不确定Linux,但我相信它保留1GB)

这意味着您的流程有2-3 GB。

在这个领域,需要考虑几个方面:

  • 您的可执行文件(以及所有动态链接的库)都被内存映射到它中
  • 每个线程需要一个堆栈

以及其他一些其他细节。

重点是,实际上使用的内存并不重要。但是很多不同的部分必须适应这个记忆空间。由于它们没有紧密地包装在它的一端,它们片段内存空间。想象一下,为简单起见,您的可执行文件被映射到此内存空间的中间。这将你的3GB分成两个1.5GB的块。现在假设您加载了两个动态库,它们将这两个块细分为四个750MB。然后你有几个线程,每个线程需要更多的内存块,进一步分割剩余的区域。当然,实际上每个都不会放在每个连续块的确切中心(这是一个非常愚蠢的分配策略),但是,所有这些内存块都细分了可用的内存空间,切断了它分成许多小块。

您可能有600MB内存空闲,但很可能没有600MB 连续内存可用。因此,单个600MB分配几乎肯定会失败,六个100MB分配可能会成功。

对于您可以分配的内存大小没有固定的限制。答案是“它取决于”。这取决于进程内存空间的精确布局。但是在32位机器上,你不可能在一次分配中分配500MB或更多。