可能的重复:
ConcurrentBag 中可能存在内存泄漏吗? https://stackoverflow.com/questions/5353164/possible-memoryleak-in-concurrentbag
Edit1:
实际的问题是。您能否确认这一点,或者我的样本是否错误并且我遗漏了一些明显的东西?
我认为 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 设为 250 KB 或 100 GB,具体取决于我添加到包中的数据量。数据和包都会消失。
当我用 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 可能很快,但作为具有相同对象生命周期的 List 的简单替换,它毫无用处。
如果我在主线程上创建 ConcurrentBag,只要线程处于活动状态,我就会保留它。这不是我所期望的,它可能会导致严重的痛苦。