1

我使用三维 char 数组实现了一个布隆过滤器(位表),它运行良好,直到它无法再分配内存并给出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 位平台开发的。

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

4

3 回答 3

4

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

您可以使用 SysInternals 的 VMMap 实用程序更深入地了解进程的虚拟内存映射。您可能能够更改 DLL 的基地址,使其不会位于地址空间的其他空白区域的中间。但是,您获得超过 650 MB 的可能性很小。

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

于 2012-04-28T17:16:50.637 回答
2

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

操作系统保留了其中的一部分(Windows 上默认有一半,给你自己 2GB。我不确定 Linux,但我相信它会保留 1GB)

这意味着您有 2-3 GB 的空间用于您自己的进程。

在这个空间中,需要满足以下几点:

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

还有很多其他的细节。

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

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

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

于 2012-04-28T17:15:16.800 回答
1

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

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

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

于 2012-04-28T17:08:26.577 回答