編集1:
実際の質問はです。これを確認できますか、それとも私のサンプルが間違っていて、明らかな何かが欠けていますか?
ConcurrentBagは、順序付けされていないリストの単純な代替品だと思いました。しかし、私は間違っていました。ConcurrentBagは、作成中のスレッドにThreadLocalとして自分自身を追加しますが、これは基本的にメモリリークを引き起こします。
class Program
{
static void Main(string[] args)
{
var start = GC.GetTotalMemory(true);
new Program().Start(args);
Console.WriteLine("Diff: {0:N0} bytes", GC.GetTotalMemory(true) - start);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Thread.Sleep(5000);
}
private void Start(string[] args)
{
for (int i = 0; i < 1000; i++)
{
var bag = new ConcurrentBag<byte>();
bag.Add(1);
byte by;
while (bag.TryTake(out by)) ;
}
}
バッグに追加するデータの量に応じて、Diffを250KBまたは100GBにすることができます。データもバッグもなくなります。
Windbgでこれに侵入し、!DumpHeapタイプの並行処理を実行すると
...。
000007ff00046858 1 24 System.Threading.ThreadLocal`1+GenericHolder`3[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System],[System.Threading.ThreadLocal`1+C0[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System]], mscorlib],[System.Threading.ThreadLocal`1+C0[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System]], mscorlib],[System.Threading.ThreadLocal`1+C0[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System]], mscorlib]]
000007feed812648 2 64 System.Collections.Concurrent.ConcurrentStack`1[[System.Int32, mscorlib]]
000007feece41528 1 112 System.Collections.Concurrent.CDSCollectionETWBCLProvider
000007ff000469e0 1000 32000 System.Threading.ThreadLocal`1+Boxed[[System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]], System]]
000007feed815900 1000 32000 System.Collections.Concurrent.ConcurrentStack`1+Node[[System.Int32, mscorlib]]
000007ff00045530 1000 72000 System.Collections.Concurrent.ConcurrentBag`1+ThreadLocalList[[System.Byte, mscorlib]]
空のConcurrentBagを作成して、一部のワーカースレッドにデータを追加させると、ConcurrentBagとそのデータは、作成中のスレッドがまだ生きている限りそこにあります。
このようにして、数GBのメモリリークが発生しました。リストとロックを使用してこれを「修正」しました。ConcurrentBagは高速かもしれませんが、同じオブジェクトの有効期間を持つリストの単純な置き換えとしては役に立ちません。
メインスレッドでConcurrentBagを作成した場合、スレッドが存続している限り、それを保持します。これは私が期待することではなく、大きな痛みを引き起こす可能性があります。