代码之家  ›  专栏  ›  技术社区  ›  Nitin Midha

在什么情况下,我们需要打电话给GC。收集两次

  •  9
  • Nitin Midha  · 技术社区  · 14 年前

    我们有一个WPF应用程序,基于与mmvvvvm模式的统一。在应用程序生命周期中,可以有几个项目生命周期,在每个项目生命周期之后,我们进行手动分解,并尝试释放视图模型的所有引用。对于具有Unity的事件订阅,我们使用弱引用。所以我们假设在崩溃之后,我们可以调用gc-collect,这样所有垃圾对象都是垃圾收集的。我们还有另外一个手动取消订阅所有事件的选项,但是我们更喜欢垃圾收集,因为它将为我们清除大约200MB的内存,这将有助于新项目的加载。

    有一个例子,我们观察到,如果我只调用gc.collect一次,它的引用将在内存中保留一段时间。

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

    但如果我连续两次尝试调用GC,它会很好地清除所有内容。

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

    任何想法或指示都将受到高度赞赏。

    更新:

    类中没有定义终结器。

    现在我也在考虑一个案例,在这个案例中,这个对象被引用到另一个可能有终结器的对象中。在我们的框架中,我们只有dbprovider的终结器,所以我不认为是这样的。

    4 回复  |  直到 8 年前
        1
  •  11
  •   Jon Skeet    14 年前

    听起来你有一个定稿器,基本上-如果你只打电话给 GC.Collect() 一旦完成,终结器将完成,但未收集终结的对象。

    这是否代表一个bug是另一回事。一般来说,对于需要执行的终结器来说,这不是一个好主意,但在您的情况下,这可能是可以的。

        2
  •  6
  •   Henk Holterman    14 年前

    如果我只调用gc.collect一次,它的引用将在内存中保留一段时间。

    不是很奇怪。当一个对象有一个终结器(并且没有对其调用gc.SuppressFinalize())时,它得到一个执行暂停(它是 已收集,以便终结器可以使用有效对象运行)。此对象引用的所有实例也将得到执行的暂停。需要通过GC进行第二轮清理。

    另一方面,大多数程序,包括大型和复杂的程序,都应该能够在不调用gc.collect()的情况下运行,即使只调用一次。你想打两次电话…

    在每一个项目生命周期之后,我们都会进行手动分解

    听起来很复杂,很容易避免…有几条推荐信 进入之内 您的域/视图模型?理想情况下,您只需剪切1或2个对“主”对象的引用,然后将其忽略。

        3
  •  0
  •   Karthik Mahalingam    14 年前

    @Nitin,我不确定我的建议是否对您有帮助,但是根据经验,我们应该避免显式地调用gc.collect()。因为它可能会导致性能问题。相反,尝试遵循正确的处理模式。

        4
  •  0
  •   Ian Ringrose    8 年前

    您有一个弱引用,您希望将其设置为空,因为您调用GC,并且您认为没有任何东西可以使对象保持活动状态。

    我不知道.NET中实现的引用有多弱,但它们很可能会延迟对象的收集,并使用像finalizers这样的系统。

    或者可能是您有一个需要最终确定的对象,因为您没有对其调用Dispose()。(非常常见于WPF或WinForms)

    要了解这一点,您需要使用memoryProfiler,至少要花一天的时间学习如何使用任何内存分析器,因为您将获得有关WPF内部对象的大量数据。我个人会下载一个免费的 Redgate’s memory profiler 看看有什么问题,有什么支持也很有帮助。(其他内存分析程序也可以很好地工作,在很大程度上,这取决于您习惯了什么。)