Возможный дубликат:
Возможная память в ConcurrentBag?
Edit1:
Реальный вопрос. Можете ли вы подтвердить это или мой образец неправильно, и я не вижу ничего очевидного?
Я думал, что ConcurrentBag просто заменяет список unorderd. Но я был неправ. 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 250 КБ или 100 ГБ в зависимости от того, сколько данных я добавляю в пакеты. Данные и мешки уходят.
Когда я врываюсь в это с помощью Windbg, и я делаю Параметр DumpHeap Concurrent
....
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 и его данные будут там, пока создающий поток все еще жив.
Таким образом, я получил утечку памяти в несколько ГБ. Я "исправил" это, используя список и блокировки. ConcurrentBag может быть быстрым, но бесполезно, как простая замена списка с тем же самым сроком жизни объекта.
Если я когда-либо создаю ConcurrentBag в основном потоке, я буду хранить его до тех пор, пока поток будет жив. Это не то, что я ожидаю, и это может вызвать серьезную боль.