サイズが 10 6 × 10 6要素の 2 次元整数配列を作成したいと考えています。このために、boost ライブラリを使用しています。
boost::multi_array<int, 2> x(boost::extents[1000000][1000000]);
ただし、次の例外がスローされます。
'std::bad_alloc'
what(): std::bad_allocのインスタンスをスローした後に呼び出される終了
問題の解決方法を教えてください。
そんなに巨大な配列を割り当てたくありません。メモリは約 4 テラバイトです。
その配列で何をしたいかによって、次の 2 つのオプションを検討する必要があります。
外部データ構造。アレイはハード ドライブに書き込まれます。最近アクセスされた部分も RAM にあるため、アクセス方法によってはかなり高速になる可能性がありますが、もちろん完全に RAM にある場合ほど高速になることはありません。外部データ構造については STXXL をご覧ください。
この方法には、配列内のすべての要素にアクセスできるという利点があります (2 番目の方法とは対照的です)。ただし、問題はまだ残っています。少なくとも一般的なデスクトップ アプリケーションについて話している場合、4 テラバイトはハード ドライブ上でも非常に巨大です。
スパース データ構造。その配列から実際にはいくつかのアイテムしか必要としないが、これらのアイテムをサイズ 10⁶ ⨯ 10⁶ のスペースでアドレス指定したい場合は、配列を使用せず、マップのようなものまたは両方の組み合わせを使用します。 1024 x 1024 要素の「ブロック」としましょう。これらのブロックを、ブロック インデックス (座標を 1024 で割った値) をキーとしてマップに配置します。
この方法には、自分で簡単に作成できるため、別のライブラリにリンクする必要がないという利点があります。ただし、10⁶ ⨯ 10⁶ の座標空間全体に分散された要素にアクセスする場合、またはすべての値が必要な場合でも、約 4TB (さらに少し多く) のメモリを使用するという欠点があります。この巨大な「仮想」配列のスマートな部分のみに実際にアクセスする場合にのみ機能します。
次の (テストされていない) C++ コードは、これを示しているはずです。
class Sparse2DArray
{
struct Coord {
int x, y;
Coord(int x, int y) : x(x), y(y) {}
bool operator<(const Coord &o) const { return x < o.x || (x == o.x && y < o,y); } // required for std::map
};
static const int BLOCKSIZE = 1024;
std::map<Coord, std::array<std::array<int,BLOCKSIZE>,BLOCKSIZE> blocks;
static Coord block(Coord c) {
return coord(c.x / BLOCKSIZE, c.y / BLOCKSIZE);
}
static Coord blockSubCoord(Coord c) {
return coord(c.x % BLOCKSIZE, c.y % BLOCKSIZE);
}
public:
int & operator[](int x, int y) {
Coord c(x, y);
Coord b = block(c);
Coord s = blockSubCoord(c);
return blocks[b][s.x][s.y];
}
};
a の代わりに(ハッシュ マップ)std::map
を使用することもできますが、型std::unordered_map
の代わりにハッシュ関数を定義する(または代わりに使用する) 必要があります。operator<
Coord
std::pair
この方法で配列を作成すると、配列はスタック上に作成され、スタックのサイズは制限されます。したがって、その大きな配列を割り当てるのに十分なスペースがないため、プログラムはクラッシュします。
これを解決するには 2 つの方法があります。 new キーワードを使用してヒープ上に配列を作成できますが、後で削除する必要があります。そうしないとメモリ リークが発生します。スタックはまだ有限です。
もう 1 つの方法は、std::vector
内部std::vector
で使用してメモリを処理させることです。
10 6 ×10 6行列を作成する意図は何ですか? 疎行列 (つまり、10 6有限要素の熱伝達問題の拡散行列) を作成しようとしている場合は、既存の線形代数ライブラリの使用を検討する必要があります。たとえば、trilinosプロジェクトは、作成しようとしているような大規模な疎行列の解決をサポートしています。