1

3 次元の char 配列を使用してブルーム フィルター (ビット テーブル) を実装しましたが、メモリを割り当てることができなくなり、 bad_allocメッセージが表示されるまではうまく機能します。600MB を割り当てた後、次の拡張リクエストでこのエラーが発生します。

ブルーム フィルター (配列) は、8 ~ 10 GB の大きさになると予想されます。

ビットテーブルを割り当てる(展開する)ために使用したコードは次のとおりです。

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 ビット プラットフォームを使用して開発されています。

8 GB RAM を搭載した 64 ビット プラットフォーム (サーバー) で実行されます。

4

3 に答える 3

4

32 ビット プログラムは、仮想メモリ アドレス空間からメモリを割り当てる必要があります。コードとデータのチャンクを格納し、メモリはそれらの間の穴から割り当てられます。はい、期待できる最大値は約 650 メガバイトで、利用可能な最大のホールです。そこから急激に下がります。1 つの巨大な配列ではなく、ツリーやリストのように、データ構造をよりスマートにすることで解決できます。

SysInternals の VMMap ユーティリティを使用すると、プロセスの仮想メモリ マップをより深く理解できます。DLL のベース アドレスを変更して、それ以外の場合はアドレス空間の空の領域の真ん中に配置されないようにすることができる場合があります。ただし、650 MB をはるかに超える可能性は低いです。

64 ビット オペレーティング システムには、より多くの余裕があります。オペレーティング システム コンポーネントは 64 ビット モードで実行されるため、32 ビット プロセスには 4 ギガバイトのアドレス空間があります。プロセスがすべてを使用できるようにするには、 /LARGEADDRESSAWARE リンカー オプションを使用する必要があります。それでも、それは 64 ビット OS でしか機能せず、プログラムは依然として 32 ビット OS を爆撃する可能性があります。本当に多くの VM が必要な場合、最も簡単な方法は、64 ビット OS を前提条件にして、x64 をターゲットとするプログラムをビルドすることです。

于 2012-04-28T17:16:50.637 に答える
2

32 ビット マシンでは、4GB のアドレス空間が提供されます。

OS はこれの一部を予約します (Windows ではデフォルトでその半分で、2GB を自分で使用できます。Linux についてはわかりませんが、1GB を予約していると思います)。

これは、独自のプロセスに 2 ~ 3 GB あることを意味します。

このスペースには、いくつかのものが収まる必要があります。

  • 実行可能ファイル (および動的にリンクされたすべてのライブラリ) は、それにメモリ マップされます。
  • 各スレッドにはスタックが必要です
  • ヒープ

他にもかなりの数の核心的なビットがあります。

ポイントは、実際にどれだけのメモリを使用するかは問題ではないということです。しかし、多くの異なる要素がこのメモリ空間に収まる必要があります。片端にぎっしり詰まっていないので、バラバラになってしまいますメモリ空間。簡単にするために、実行可能ファイルがこのメモリ空間の中央にマップされていると想像してください。これにより、3GB が 2 つの 1.5GB チャンクに分割されます。ここで、2 つの動的ライブラリをロードすると、それらの 2 つのチャンクが 4 つの 750 MB のチャンクに分割されるとします。次に、いくつかのスレッドがあり、それぞれがさらにメモリのチャンクを必要とし、残りの領域をさらに分割します。もちろん、実際には、これらのそれぞれが隣接する各ブロックの正確な中心に配置されることはありません (これはかなりばかげた割り当て戦略です) が、それでも、これらすべてのメモリのチャンクは、使用可能なメモリ空間を細分化し、分割します。多くの小さな断片に。

600MB の空きメモリがあるかもしれませんが、600MB の連続したメモリを利用できる可能性はほとんどありません。したがって、単一の 600MB 割り当てがほぼ確実に失敗する場合でも、6 つの 100MB 割り当てが成功する可能性があります。

割り当てることができるメモリのチャンクの大きさに一定の制限はありません。答えは「場合による」です。プロセスのメモリ空間の正確なレイアウトに依存します。しかし、32 ビット マシンでは、1 回の割り当てで 500MB 以上を割り当てることはほとんどありません。

于 2012-04-28T17:15:16.800 に答える
1

32ビットプロセスがアクセスできるメモリ内データの最大数は、理論的には4GBです(実際には多少小さくなります)。そのため、一度に10GBのデータをメモリに保存することはできません(OSがそれ以上をサポートしている場合でも)。また、メモリを動的に割り当てている場合でも、使用可能な空きストアはスタックサイズによってさらに制限されます。

プロセスで使用可能な実際のメモリは、実行可能ファイルを生成するコンパイラ設定によって異なります。

本当にそれだけ必要な場合は、ファイルシステムにデータ(の一部)を保持することを検討してください。

于 2012-04-28T17:08:26.577 に答える