我们在我们的windows服务中使用Funq来执行一些预定的任务,对于每一轮,我们创建一个子容器来创建我们所有的对象,并在最后处置子容器,我们发现这个子容器创建的元素不是GC,因为根容器有子容器的集合,这些子容器在调用dispose子容器后会留在那里。这段代码重现了我们的问题,并将消耗(并保留) 800MB内存。
对我们来说,这很令人惊讶,这样使用funq是不是错误的模式,在这种情况下,我们应该如何使用它?或者这只是一个bug?
谢谢
public class Dummy
{
public string Content { get; set; }
public void Generate(int size)
{
this.Content = new string('X', size);
}
}
class Program
{
static void Main(string[] args)
{
var container = new Container();
container.RegisterAutoWired<Dummy>().ReusedWithin(ReuseScope.Container);
int size = 20000;
for (int i = 0; i < size; i++)
{
using (var c = container.CreateChildContainer())
{
var d= c.Resolve<Dummy>();
d.Generate(size);
}
PrintInfo(i);
}
Console.ReadLine();
}
private static void PrintInfo(int i)
{
if (i%1000 == 0)
{
int divide = 1024*1024;
GC.Collect();
var p = System.Diagnostics.Process.GetCurrentProcess();
Console.WriteLine(p.WorkingSet64/divide + "MB");
Console.WriteLine(p.PrivateMemorySize64/divide + "MB");
}
}
}发布于 2013-03-25 03:00:42
通过查看Funq sources中的Container.cs (最后一次更新是在2011年),我可以断定它泄漏了子容器。
CreateChildContainer方法创建新的容器,将其与父容器连接,并将创建的引用添加到childContainers堆栈。
只有两个地方使用childContainers堆栈:
因此,如果你创建子容器,然后将其销毁(但不是其父容器)--对被处置的子容器的引用将保留在父容器中,因为没有清理代码可以将被处置的引用从父堆栈中移除。
也许你可以通过创建代理子容器(只有一次),然后从它派生所有真正的子容器来解决这个问题。由于Dispose方法不会将对象转换为不可用状态-您可以通过一遍又一遍地为代理子对象调用Dispose来清理所有子对象:
var container = new Container();
container.RegisterAutoWired<Dummy>().ReusedWithin(ReuseScope.Container);
int size = 20000;
var proxy = container.CreateChildContainer()
for (int i = 0; i < size; i++)
{
using (proxy)
using (var c = proxy.CreateChildContainer())
{
var d= c.Resolve<Dummy>();
d.Generate(size);
}
PrintInfo(i);
}发布于 2014-01-15 20:50:28
这个问题是由于父容器有一个子容器的引用,即使子容器被释放了。垃圾收集器在大多数情况下都工作得很好,但我认为这是最基本的情况。最简单的方法是,如果容器父对象不为空,则从父对象的子集合中删除容器引用。
您可以从this unit test(您的代码片段)和its implementation查看该方法。
https://stackoverflow.com/questions/15512035
复制相似问题