3

重複
の可能性: ConcurrentBag でメモリリークの可能性がありますか?

アプリで重大なメモリ リークが発生しています。メソッドの1つでローカルのconcurrentBagコレクションに追加したすべてのデータは収集されませんでした。

この単純なコードは、私がそれをどのように使用するかを示しています:

void Main()
{
    var l = new List<int>(){1,2,3,4};
    Func(l);
    l.Clear();
    l=null;
}

void Func(List<int> list)
{
    var bag = new ConcurrentBag<int>();
    Parallel.ForEach(list, k=> bag.Add(++k));

    list.Clear();

    foreach(int i in bag) //I know, I doing it wrong.
    {
        list.Add(i);
    }
}

私が期待すること: バッグが作成され、メソッド「Func」で破棄されます。

私が見ているもの: バッグは破棄されず、Parallel.ForEach で作成されたすべてのスレッドを保持し、追加したすべてのデータを保持します。=(

さて、リストに追加するときに、「TryTake」を使用してバッグからアイテムを削除できます。しかし、空のバッグはまだメモリに保持されています。

現在、ConcurrentBag の代わりに List を使用して問題を解決しています。しかし、これを記憶プロファイラーで見たので、よく眠れません。私の英語でごめんなさい=)

アップデート

メソッド「Func」を変更します。

void Func(List<int> list)
{
    var bag = new ConcurrentBag<int>();
    Parallel.ForEach(list, k=> bag.Add(++k));

    list.Clear();

    int i;
    while(bag.TryTake(out i))
    {
        list.Add(i);
    }

    bag = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

次に、VS でプロジェクトを作成し、プログラムをコンパイルして実行します。このインスタンス グラフは、プログラムがすべての作業を完了してから 10 分後に収集したメモリ スナップショットから ".Net Memory Profiler 4.0" によって作成されました。

http://xmages.net/storage/10/1/0/f/d/upload/4c67f305.jpg (申し訳ありませんが、画像を投稿できません)

4

1 に答える 1

9

これは、並行バッグがスレッドのローカル ストレージにアイテムを追加するためです。スレッドのローカル ストレージからバッグへの参照は強力な参照であるため、バッグにアイテムが 1 つ残っている限り、少なくとも 1 つのスレッドがバッグを参照し、それが収集されないことが保証されます。バッグのすべてのアイテムを消費するか、別の容器を使用してください。

参照してください: ConcurrentBag でメモリリークの可能性がありますか?

于 2012-02-13T07:18:07.350 に答える