0

150,000 個のファイルを分析するプログラムがあります。Valgrind はメモリ リークを報告しませんが、プログラムは時間の経過とともに遅くなります。

一部の問題は、std::string の使用頻度が高すぎたり、mktime に時間がかかりすぎたりすることに関連していました。( C++ が 70,000 ファイルの読み取りに時間の経過とともに遅くなる を参照)

しかし、それでも時間の経過とともに遅くなります。 Lotharyxは、コンテナーの使用がヒープの断片化を引き起こしていることを示唆しました。

さまざまな STL コンテナーの長所と短所に関するさまざまなフローチャートを読みましたが、よくわかりませんでした。

以下の疑似コードでは、ヒープの断片化を避けるために正しい選択をしたかどうか確信が持てません。

fileList.clear()
scan all disks and build "fileList", a std::set of file paths matching a pattern.

// filepaths are named by date, eg 20160530.051000, so are intrinsically ordered 

foreach(filePath in fileList)
{
    if (alreadyHaveFileDetails(filePath))
        continue;

    // otherwise
    collect file details into a fileInfoStruct;  // like size, contents, mod 

    fileInfoMap[time_t date] = fileInfoStruct;
}

// fileInfoMap is ordered collection of information structs of about 100,000 files

// traverse the list in order
foreach (fileInfo in fileInfoMap)
{
    if (meetsCondition(fileInfo))
    {
        TEventInfo event = makeEventInfo()
        eventList.push_back(event);
    }
}

そして、上記のシーケンスは永遠に繰り返されます。

したがって、コンテナの選択のために、私は使用しました(または必要です):

fileList-- 150,000 のパス名を含む一意の文字列のリスト。
std::set を選択したのは、重複を自動的に処理し、並べ替え順序を自動的に維持するためです。ランダム アクセスはなく、エントリを追加し、(手動または自動で) 並べ替え、それらを反復処理するだけです。

fileInfoMap-- ファイルの日付に対応する time_t タイムスタンプをキーとする構造体の配列。std::map を選択しました。これも 150,000 エントリになるため、多くのメモリを占有します。ランダム アクセスはありません。一方の端にエントリを追加するだけです。それらを反復処理し、必要に応じて途中からエントリを削除する必要があります。

eventList-- 「イベント」構造の小さなリスト、たとえば 50 項目。std::vector を選択しました。本当に理由がわからない。ランダムアクセスはありません。一方の端にエントリを追加するだけで、後でコレクションを反復処理します。

私はC ++にかなり慣れていません。ご検討いただきありがとうございます。

4

1 に答える 1

2

メモリ管理に関して、コンテナーは 2 つの大きなファミリーに属します。すべての要素をまとめて割り当てるファミリーと、要素を個別に割り当てるファミリーです。

vector と deque は最初のファミリに属し、list、set および map は 2 番目のファミリに属します。

グローバルな再配置をサポートしていないコンテナーに対して要素が継続的に追加および削除されると、メモリの断片化が発生します。

この問題を回避する 1 つの方法は、vectors を使用し、" reserve" を使用してメモリの必要性を予測して再配置を減らし、挿入時にデータをソートしておくことです。

もう1つの方法は、「リンクベースのコンテナ」(リスト、セットなど)を使用して、より大きなチャンクからメモリを割り当てるアロケータを提供し、要素の挿入/削除ごとに生のmalloc/freeを呼び出す代わりにそれらをリサイクルすることです。

std::allocatorを見てください

std::allocator から派生させ、必要なすべてのロジックを追加してallocate/関数をオーバーライドし、使用するコンテナーのオプションのテンプレート パラメーターとして渡すことで、アロケーターを簡単に作成できます。deallocateyourallocator

于 2016-07-04T17:07:08.147 に答える