2012-04-28 68 views
0

我使用三维char数组实现了一个布隆过滤器(位表),它运行良好,直到它达到不能再分配内存并给出消息的一个点为止。分配600MB后,它会在下一个扩展请求中出现此错误。为什么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位平台开发的。

它运行在具有8GB RAM的64位平台(服务器)上。

+1

此代码甚至伤害眼睛,毫无疑问,它不起作用。 – 2012-04-28 17:03:45

+1

640MB应该足够每个人。哎呀,我是否大声说出来?我的意思是,你有多少内存,这是一个64位的环境? – 2012-04-28 17:04:24

+3

您使用的是什么系统?你不能指望一个32位系统有一个大小为6GB的数组[因为有4GB的虚拟地址,如果我没有记错的话,其中约1GB是保留给内核的,至少在linux下] – amit 2012-04-28 17:04:28

回答

5

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

您可以通过SysInternals的VMMap工具获得更多关于流程的虚拟内存映射的信息。您可能能够更改DLL的基地址,因此它不会坐在地址空间的其他空白区域的中间。然而,你会得到650 MB以上的赔率很差。

在64位操作系统上有更多的呼吸空间,32位进程拥有4千兆字节的地址空间,因为操作系统组件运行在64位模式下。您必须使用/ LARGEADDRESSAWARE链接器选项来允许进程全部使用它。尽管如此,它只适用于64位操作系统,但您的程序仍然可能在32位操作系统上发生爆炸。当你真的需要这么多的虚拟机时,最简单的方法就是将64位操作系统作为先决条件,然后构建一个定位到x64的程序。

+0

谢谢。你是否说如果我改变平台,这个问题根本不会出现? – John 2012-04-28 17:19:35

+0

不,64位地址空间仅受分页文件大小的限制。 – 2012-04-28 17:20:43

+0

@HansPassant:不正确。在Unix机器上,系统管理员可以设置单个进程消耗的虚拟内存的硬性和软性限制。用户可以提高软限制,但不能高于硬限制。但是约翰需要编译并在64位机器上运行的帖子的要点是正确的。 +1。 – 2012-04-28 17:23:59

1

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

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

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

1

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

操作系统保留一些这方面的(一半是在默认情况下在Windows上,给你2GB自己。我不知道关于Linux,但我相信它保留1GB)

这意味着你必须2- 3 GB到您自己的进程。

进入这个空间里,几件事情需要适应:

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

和其他一些基本的位。

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

您可能有600MB的内存空间,但很可能不会有600MB的连续的内存可用。因此,如果单个600MB分配几乎肯定会失败,那么六个100MB分配可能会成功。

对于您可以分配多大的内存空间没有固定的限制。答案是“视情况而定”。这取决于流程内存空间的精确布局。但在32位机器上,您不太可能在单个分配中分配500MB或更多。