0

大きなテキスト ファイル (~300MB) からベクトルの配列にデータを読み込むとします (vector<string> *Data列数が既知であると仮定します)。

//file is opened with ifstream; initial value of s is set up, etc...


Data = new vector<string>[col];
string u;
int i = 0;

do
{       
    istringstream iLine = istringstream(s);

    i=0;
    while(iLine >> u)
    {
        Data[i].push_back(u);
        i++;
    }
}
while(getline(file, s));

このコードは小さなファイル (<50mb) では正常に機能しますが、大きなファイルを読み取るとメモリ使用量が指数関数的に増加します。istringstreamループのたびにオブジェクトを作成することに問題があると確信しています。istringstream iLine;ただし、両方のループの外側で定義し、各文字列をストリームに入れiLine.str(s);、内側の while-loop ( iLine.str(""); iLine.clear();) の後でストリームをクリアすると、同じ順序でメモリ爆発が発生します。発生する質問:

  1. なぜistringstreamこのように振る舞うか;
  2. それが意図した動作である場合、上記のタスクをどのように達成できますか?

ありがとうございました

編集:最初の答えに関しては、コードの後半で配列によって割り当てられたメモリをクリーンアップします:

for(long i=0;i<col;i++)
    Data[i].clear();
delete []Data;

FULL COMPILE-READY CODE (ヘッダーを追加):

int _tmain(int argc, _TCHAR* argv[])
{
ofstream testfile;
testfile.open("testdata.txt");

srand(time(NULL));

for(int i = 1; i<1000000; i++)
{
    for(int j=1; j<100; j++)
    {
        testfile << rand()%100 << " ";
    }

    testfile << endl;
}

testfile.close();

vector<string> *Data;

clock_t begin = clock();

ifstream file("testdata.txt"); 

string s;

getline(file,s);

istringstream iss = istringstream(s);

string nums;

int col=0;

while(iss >> nums)
{
    col++;
}

cout << "Columns #: " << col << endl;

Data = new vector<string>[col];

string u;
int i = 0;

do
{

    istringstream iLine = istringstream(s);

    i=0;

    while(iLine >> u)
    {
        Data[i].push_back(u);
        i++;

    }

}
while(getline(file, s));

cout << "Rows #: " << Data[0].size() << endl;

for(long i=0;i<col;i++)
        Data[i].clear();
    delete []Data;

clock_t end = clock();

double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;

cout << elapsed_secs << endl;

getchar();
return 0;
}
4

2 に答える 2

0

これは istringstream の問題ではないと真剣に考えています (特に、ループ外の iLine コンストラクターで同じ結果が得られる場合)。

おそらく、これは std::vector の通常の動作です。それをテストするには、まったく同じ行を実行してみてくださいData[i].push_back(u);。あなたの記憶がこのように成長するかどうかを確認してください。そうでない場合は、問題がどこにあるかがわかります..

ライブラリによって異なりますが、 vector::push_back は、より多くのスペースが必要になるたびに、その容量を 1.5 倍 (Microsoft) または 2 倍 (glib) 拡張します。

于 2013-01-31T07:15:48.810 に答える
0

vector<>幾何学的にメモリを増やします。典型的なパターンは、拡張が必要になるたびに容量を 2 倍にすることです。そのようなしきい値の直後にループが終了すると、多くの余分なスペースが割り当てられますが、未使用のままになる可能性があります。shrink_to_fit()完了したら、各ベクトルを呼び出すことができます。

さらに、C++ アロケーター (または plain でさえもmalloc()) によって割り当てられたメモリは、多くの場合、OS に返されず、プロセス内部の空きメモリ プールに残されます。これにより、さらに明らかな成長が見られる可能性があります。また、プロセスの外部から結果shrink_to_fit()が見えなくなる可能性があります。

最後に、小さな文字列 (「2 桁の数字」) がたくさんある場合、stringオブジェクトのオーバーヘッドがかなり大きくなる可能性があります。実装が小さな文字列の最適化を使用している場合でも、典型的な文字列は 16 または 24 バイト (サイズ、容量、データ ポインター、または小さな文字列バッファー) を使用していると思いますsize_type。64 ビットのプラットフォームではおそらくそれ以上です。これは、3 バイトのペイロードに対して大量のメモリです。

だから私はあなたがの通常の動作を見ていると思いますvector<>

于 2013-01-31T07:17:53.870 に答える