ここで何が起こっているのかはまだ完全にはわかりませんが、メモリのオーバーヘッドが少なくとも問題の一部であるようです。ただし、全体のメモリ消費量は、data
構造体に必要なメモリの約 4 倍です。27M のレコードが 14GB を占有している場合、1 レコードあたり約 500 バイトありますが、占有されるスペースは 56GB です。私には、これは、ここに示されているよりも多くのデータが保存されているか、少なくとも一部のデータが複数回保存されていることを示しています。
そして、「ヒープストレージの追加データ」は、実際には私にとっては役に立ちません。Linux では、メモリ割り当てには、最小で約 32 バイトのデータが必要です。16 バイトのオーバーヘッドがあり、割り当てられたメモリ自体が 16 バイトの倍数を占有します。
したがってdata *
、マルチマップに格納された 1 つのレコードには、次のものが必要です。
16 bytes of header for the memory allocation
8 bytes for pointer of `value1`
8 bytes for pointer of `value2`
16 bytes of header for the string in value1
16 bytes of header for the string in value2
8 bytes (on average) "size rounding" for string in value 1
8 bytes (on average) "size rounding" for string in value 2
?? bytes from the file. (X)
80 + X bytes total.
次にchar *
、マルチマップに次のものがあります。
16 bytes of header for the memory allocation.
8 bytes of rounding on average.
?? bytes from the file. (Y)
24 + Y bytes total.
マルチマップの各ノードには 2 つのポインターがあります (ある種のバイナリ ツリーであると想定しています)。
16 bytes of header for the memory allocation of the node.
8 bytes of pointer to "left"
8 bytes of pointer to "right"
32 bytes total.
そのため、ファイル内のエントリごとに 136 バイトの「オーバーヘッド」が発生します。27M レコードの場合、4GB をわずかに上回ります。
先ほど言ったように、ファイルにはエントリごとに 500 バイトが含まれているため、14GB になります。
全部で18GBです。
つまり、どこかで何かが漏れているか、計算が間違っています。ここでの計算は間違っているかもしれませんが、上記のすべてが計算したスペースの 2 倍になるとしても、まだ 20GB は計算されていません。
確かに、メモリを節約するためにできることがいくつかあります。
1) に 2 つの文字列を割り当てないでくださいdata
。最初に両方の長さを計算し、メモリの 1 つの塊を割り当て、文字列を互いに直後に格納します。
data(char* _value1, char* _value2)
{
int len1 = strlen(_value1);
int len2 = strlen(_value2);
value1 = new char[len1 + len2 +2];
strcpy(value1,_value1);
value2 = value1 + len1 + 1;
strcpy(value2,_value2);
}
これにより、エントリごとに平均 24 バイトが節約されます。賢く、data、value1、および value2 に一度にメモリを割り当てることで、さらに節約できる可能性があります。しかし、それは少し「賢すぎる」かもしれません。
2) 大量のdata
アイテムを割り当てて、一度に 1 つずつ配布することも役立ちます。これが機能するには、空のコンストラクターと「setvalues」メソッドが必要です。
struct data
{
...
data() {};
...
set_values(char* _value1, char* _value2)
{
int len1 = strlen(_value1);
int len2 = strlen(_value2);
value1 = new char[len1 + len2 +2];
strcpy(value1,_value1);
value2 = value1 + len1 + 1;
strcpy(value2,_value2);
}
}
std::string v1[100], v2[100], key[100];
for(i = 0; i < 100; i++)
{
if (!read_line_from_file(key[i], v1[i], v2[i]))
{
break;
}
}
data* data_block = new data[i];
for(j = 0; j < i; j++)
{
data_block[j].setValues[v1[j].c_str(), v2[j].c_str());
m.insert(key[i].c_str(), &data_block[j]);
}
繰り返しますが、これによって大量のメモリが節約されるわけではありませんが、16 バイトの領域ごとにいくらかのメモリが節約されます。もちろん、上記は完全なコードではなく、「どのように実行できるかを示したもの」です。
3)「キー」がマルチマップのどこから来たのかはまだわかりませんが、キーがvalue1とvalue2のエントリの1つである場合、別のコピーを保存するのではなく、それらの1つを再利用できます[そのようになっていると仮定します現在行われている]。
これが本当の答えではない場合は申し訳ありませんが、「あなたがしていることの説明のどこかで何かが説明されていない」という意味での答えだと思います.
プログラムでどのような割り当てが行われるかを理解することは、間違いなく役立ちます。