【问题标题】:Why GC does not collect unused objects?为什么 GC 不收集未使用的对象?
【发布时间】:2012-01-31 22:03:02
【问题描述】:

我在实验中使用 BlockingCollection 实现了生产者/消费者模式。

PerformanceCounter c = null;
void Main()
{
    var p  =System.Diagnostics.Process.GetCurrentProcess();
    c = new PerformanceCounter("Process", "Working Set - Private", p.ProcessName);

    (c.RawValue/1024).Dump("start");
    var blocking = new BlockingCollection<Hede>();
    var t = Task.Factory.StartNew(()=>{
        for (int i = 0; i < 10000; i++)
        {
            blocking.Add(new Hede{
            Field = string.Join("",Enumerable.Range(0,100).Select (e => Path.GetRandomFileName()))
            });
        }
        blocking.CompleteAdding();
    });

    var t2 = Task.Factory.StartNew(()=>{
        int x=0;
        foreach (var element in blocking.GetConsumingEnumerable())
        {
            if(x % 1000==0)
            {
                (c.RawValue/1024).Dump("now");
            }
            x+=1;   
        }
    });
    t.Wait();
    t2.Wait();
    (c.RawValue/1024).Dump("end");
}

运行后我的内存转储:

start
211908
now
211972
now
212208
now
212280
now
212596
now
212736
now
212712
now
212856
now
212840
now
212976
now
213036
end
213172

我的内存在消费之前是211908kb,但是在从其他线程生产时它会一点一点增加。

GC 没有从内存中收集生成的对象。为什么虽然实现了生产者/消费者模式,但我的内存却增加了?

【问题讨论】:

  • 我没有看到任何 Dispose 或 Using 调用。我看到您将项目添加到集合中并且从不删除它们。我不太明白问题是什么或您要达到的目标。
  • 我真的不明白你期望发生什么?
  • 起源:它是生产者/消费者模式,我不需要从列表中删除项目。 GetConsumingEnumerable() 为我删除项目
  • 您的结果并不表明存在泄漏或任何情况。许多项目会消耗内存,而您的差异很小。运行 2 天,它可能会稳定下来。
  • 您的标题与您的问题不符! GC 确实会收集未使用的对象当它决定这样做时。由于没有 GC.Collect 调用,因此您只需在程序创建对象时进行测量。

标签: c# memory-management producer-consumer


【解决方案1】:

垃圾收集器不会一直自动释放内存。您可以在处置未使用的对象后通过调用GC.Collect(); 来强制进行垃圾回收。

【讨论】:

  • 我在t2.Wait(); 行之后尝试了GC.Collect();GC.WaitForPendingFinalizers();GC.Collect();,没关系
【解决方案2】:

BlockingCollection&lt;T&gt;contains a memory leak in .Net 4.0 默认使用的ConcurrentQueue&lt;T&gt;。我不确定这是您观察到的问题,但可能是。

它应该在即将到来的 .Net 4.5 中修复。

【讨论】:

  • 虽然 ConcurrentQueue 确实如此,但“泄漏”永远不会超过队列中未使用的部分。你通常会使用一个上限,比如new BlockingCollection&lt;Hede&gt;(100),然后你可以永远运行它。
  • @Henk,是的,但是使用问题中的代码,队列没有限制,很可能首先将其完全填充,然后才会消耗项目。如果是这样的话,那么所有的项目都会泄漏。
猜你喜欢
  • 1970-01-01
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多