我的应用中有史诗般的内存泄漏。我从未收集过我在其中一种方法中添加到本地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”处理。
我看到:bag永远不会被处置,保存在Parallel.ForEach中创建的所有线程,保存我添加的所有数据。 =(
好的,当我将它添加到列表中时,我可以使用“TryTake”从包中删除项目。但空袋仍然留在记忆中。
现在我通过使用List而不是ConcurrentBag来解决问题。但是因为我在记忆中看到这个,所以我睡不好觉。对不起我的eng =)
我改变了我的方法“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中创建项目,编译并运行我的程序。这个实例图是由内存快照中的“.Net Memory Profiler 4.0”创建的,我在程序完成所有工作后的10分钟内收集了该文件:
http://xmages.net/storage/10/1/0/f/d/upload/4c67f305.jpg (对不起,就是不能发布图片)
答案 0 :(得分:9)
这是因为并发包将项添加到线程的本地存储中。从线程的本地存储器到袋子的引用是强有力的参考,因此只要袋子中仍有1个物品,它确保至少1个线程参考袋子并且它不会被收集。消耗袋中的所有物品或使用不同的容器。