我一直在阅读新的并发集合,特别是ConcurrentBag引起了我的注意。由于ConcurrentBag在每个单独的线程上内部拥有一个本地集来使用它来跟踪项目,这意味着当线程本身超出范围时,ConcurrentBag仍将在内存中引用它。这反过来意味着线程声称的内存,以及本机资源? (请原谅我不知道.NET线程对象的确切内部工作方式)
我可以假设一个用例,你有一个全局ConcurrentBack用于多线程webservice,你有很多客户端添加任务。这些任务由线程池上的线程添加。现在,线程池是一种非常有效的管理线程的方法,但它确实根据工作量删除并创建了线程。因此,这样的Web服务有时会发现自己遇到麻烦,因为底层包仍在引用许多应该被破坏的线程。
我创建了一个快速应用来测试这种行为:
static ConcurrentBag<int> bag = new ConcurrentBag<int>();
static void FillBag() { for (int i = 0; i < 100; i++) { bag.Add(i); } }
static void PrintState() { Console.WriteLine("Bag size is: {0}", bag.Count); }
static void Main(string[] args)
{
var remote = new Thread(x =>
{
FillBag();
PrintState();
});
// empty bag
PrintState();
// first 100 items are added on main thread
FillBag();
PrintState();
// second 100 items are added on remote thread
remote.Start();
remote.Join();
// since the remote thread is gone out of scope, what happened to its local storage which is part of the bag?
PrintState();
// now force a cleanup
WeakReference weakRemoteReference = new WeakReference(remote);
remote = null;
GC.Collect();
GC.WaitForPendingFinalizers();
// Now check if the thread still exists
if (weakRemoteReference.IsAlive)
Console.WriteLine("Remote thread still exists");
PrintState();
Console.ReadLine();
输出结果证实了我的故事:
Bag size is: 0
Bag size is: 100
Bag size is: 200
Bag size is: 200
Remote thread still exists
Bag size is: 200
这种行为是否可以预期,我在测试中是否犯了错误,或者这可能被视为设计缺陷?
答案 0 :(得分:8)
ConcurrentBag
确实将事物保存在线程本地存储中,如果放弃线程,可以导致内存泄漏。但是,该实现能够从一个线程的列表中“窃取”项目以提供给另一个线程。如果您编写以下内容,可以看到这一点:
ConcurrentBag<int> MyBag = new ConcurrentBag<int>();
void DoIt()
{
for (int i = 0; i < 10; ++i)
{
MyBag.Add(i);
}
ThreadPool.QueueUserWorkItem(EmptyBag);
Console.Write("Press Enter:");
Console.ReadLine();
Console.WriteLine("{0} items in bag", MyBag.Count);
}
void EmptyBag(object state)
{
int take;
while (MyBag.TryTake(out take))
{
Console.WriteLine(take);
}
Console.WriteLine("Bag is empty");
}
如果您运行该程序并等到“Bag is empty”消息,然后按Enter键,您将看到该包确实已清空。
所以,只要从包里读出一个帖子, 最终就会被清空。即使所有项目都是由其他线程添加的。
所以,是的,可能存在内存泄漏。但实际上,如果有多个线程正在访问这个包,那么它可能不是一个问题。