代码之家  ›  专栏  ›  技术社区  ›  Trent

委托变量未垃圾收集

  •  1
  • Trent  · 技术社区  · 16 年前

    倒掉堆后有一百万的内存。

    注意:“result.Things”是一个列表,Converter是一个系统委托。

    
            public Blah Foo()
            {
                    var result = new Blah();
                    result.Things = this.Things.ConvertAll((new Converter(ToGadget)));
                    return result;
            }
            .................
            public static Gadget ToGadget(Widget w)
            {
                return new Gadget(w);
            }
    

    更新 :将“ConvertAll”更改为此值将清除委托和相应的对象引用。这表明List<gt;ConvertAll以某种方式保留了委托,或者我不明白这些东西是如何被垃圾收集的。

    
                foreach (var t in this.Things)
                {
                    result.Things.Add(ToGadget(t));         
                }
    
    3 回复  |  直到 16 年前
        1
  •  6
  •   Eric Lippert    16 年前

    使用内存分析器。

    您可以整天在StackOverflow上询问并得到一堆有根据的猜测,或者您可以在应用程序上使用内存分析器,立即查看哪些是根的,哪些是垃圾。有一些工具是专门为快速轻松地解决您的确切问题而构建的。使用它们!

        2
  •  4
  •   Reed Copsey    16 年前

    你的问题有一个主要的缺陷,这可能是引起混淆的原因:

    似乎在Foo结束后,委托和所有对象都将被标记为垃圾回收。

    CLR不会在例程结束时为集合“标记项”。相反,一旦例程结束,就不再有(活动的)对委托中引用的任何项的引用。在这一点上,它们被称为“未经雕琢的”。

    ,当CLR确定存在一定的内存压力时,垃圾收集器将执行。它将搜索并找到所有未打开的元素,并可能收集它们。

    这里的重要区别在于,时机不是可以预测的。这些物体可能 从不被收集 Foo 结束-但在某个未知的时间之后 末端。


    编辑:

    这实际上是在直接解决您的问题,顺便说一句,您可以通过强制垃圾收集来查看这是否是问题所在。打电话给Foo后,再打电话给:

    GC.Collect();
    GC.WaitForPendingFinalizers();
    

    然后检查CLR堆。在这一点上,如果您仍然在堆中获取对象,那是因为对象仍然是由某个对象扎根的。您的简化示例没有显示这种情况,但由于这是一个非常简化的示例,因此很难确定这种情况会发生在哪里。(注意:如果是这样的话,我不建议在代码中保留这个。手动调用GC.Collect()几乎总是个坏主意…)

        3
  •  2
  •   Joel Etherton    16 年前

    不管我是对是错,这种可能性打字有点滑稽。