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

.NET中的Finalize和Dispose方法有什么意义?(回答前请参阅详细信息)

  •  4
  • JohnFx  · 技术社区  · 17 年前

    我需要在拆卸对象时清理资源,但我总是发现 处置 , 定稿 和析构函数方法有点混乱。

    我发现这篇伟大的文章简明地描述了它们之间的区别,我将不得不保存下来供将来参考:
    "Difference between Destructor, Dispose and Finalize methods" - Sanjay Saini http://sanjaysainitech.blogspot.com/2007/06/difference-between-destructor-dispose.html

    我想问的基本问题是。

    如果一种语言提供了析构函数(例如c[拒绝])什么? 价值做 处置 定稿 添加到公式中?

    我只是一个习惯于旧学派的方式在毁灭者中做每件事的冷酷的人,还是我所缺少的只有把一个物体分解成三个部分才能实现的东西?

    更新:
    正如在一些回复中提到的,C实际上没有析构函数。在这一点上,认识到这一点,这个问题可能是没有意义的。当我在上面提到的文章中读到C实际上有一个单独的解构函数(显然是一个错误)时,它让我陷入了一个循环,我开始想,如果您有一个最终的析构函数来包装所有东西,那么Dispose和Finalize的意义是什么。我认为在类C的gc语言中,为对象提供denemount的单个析构函数的概念没有多大意义。

    很抱歉你们中的一些人投了反对票,但有几个人没有仔细阅读这个问题,认为我在问处理和完成之间的区别,这不是重点。

    9 回复  |  直到 17 年前
        1
  •  7
  •   Brian Genisio    17 年前

    那篇博文的作者有点困惑…

    在C中,没有“析构函数”这样的东西。仅限终结器和IDisposable。

    ~classname()方法不被称为“析构函数”。它被称为终结器。

    Dispose存在以释放代码中的资源,其中存在要从GC调用的终结器。通常,终结器调用Dispose()方法,但 "Dispose Pattern" 设置为仅处理来自终结器的非托管资源。

    您可以看到,当调用终结器时,您处于不同的线程上,并且您拥有的任何托管对象都不一定有效。因此,如果从终结器调用Dispose(),则实际上应该调用Dispose(false),它告诉“Dispose模式”只释放非托管资源。

    此外, “释放模式” 建议在调用Dispose(true)时,应取消该对象上的终结器。

        2
  •  4
  •   JP Alioto    17 年前

    只有托管对象才能自动完成。如果你想提供 隐性的 处理非托管对象时,可以使用终结器。如果你想提供 明确的 控制对象的调用方的释放,您可以允许他们调用释放。

    I like this article .

        3
  •  3
  •   Lasse V. Karlsen    17 年前

    很难回答这个问题,因为你已经链接到解释差异的文章。

    但无论如何让我试试。

    对于垃圾收集,您有不确定的内存管理,并且由于GC将运行终结器,所以您有保证,但不确定的资源管理。

    这很好,从某种意义上说,你知道事情会被清理干净。

    但是,这很糟糕,因为你不知道什么时候会发生。

    例如,如果您打开一个文件并在打开时将其锁定,不知道该文件什么时候以后可以再次打开是不好的,但是保证在某个时刻它将被关闭是很好的。

    Dispose和IDisposable通过添加确定性资源管理来解决这个问题。您可以选择何时释放资源、关闭文件、网络连接、数据库连接等。这是您的选择,当您不再需要资源时,您通常会将其丢弃。因此,当您不再需要该文件时,您将处理保持其打开的对象。对象将在内存(非确定性内存管理)中停留一段时间,但当您这样说时,文件将被关闭,准备立即再次打开。

    因此,您获得了对资源的确定性处理,并将其与非确定性内存管理结合起来,就得到了两个世界中最好的。

        4
  •  2
  •   Ðаn    17 年前

    C中的析构函数是什么样子的?#( ~Foo() )是一种完全不同的拼写方式“定稿”。

    也许事后看来,语法的选择不是最好的,因为 ~() C与 ~() 在C++中。

        5
  •  2
  •   JohnFx    17 年前

    很抱歉回答我自己的问题,但我认为我收集了各种来源的答案,其中包括一些答案是我的问题的一个简明答案,解决了在转换到GC平台时对象生命周期的差异。


    非GC对象生命周期:

    初始化: 在将第一个引用添加到对象时调用的构造函数中发生。

    Cleanup: 在析构函数中发生,该析构函数在最后一个引用对象的变量超出范围或显式设置为Nothing/null/其他对象时调用。


    GC对象生命周期:

    初始化: 在将第一个引用添加到对象时调用的构造函数中发生。

    清理(第一遍): 在Dispose方法中发生,该方法必须由客户端显式调用或在using语句结尾隐式调用。这种清理专门用于释放必须立即释放的资源,而不是等待GC。

    清理(最终通过): 发生在finalize方法中,该方法在GC的时间表上调用,可以延迟。如果实现了Finalize方法,则除非以前对对象(通常从Dispose方法中)调用了gc.SuppressFinalize以将其标记为已清除,否则将调用该方法。


    我说得对吗?如果我错过了什么,请随意编辑。

        6
  •  1
  •   Jason Coyne    17 年前

    C不提供析构函数,所以您的问题有点无意义?

        7
  •  1
  •   Jason Coyne    17 年前

    我不确定析构函数和终结器之间的推理,但存在Dispose,以便在垃圾收集器到达对象之前释放资源(可能永远不会!)

        8
  •  1
  •   JoshBerke    17 年前

    等待终结器运行以释放资源的问题是,它不会以可预测的确定性方式运行。当GC准备销毁对象时调用终结器,这可以在应用程序中的任何时候发生。

    这就是为什么你要处理。它允许您在已知的时间点确定性地释放资源,确保资源将被释放。否则,您将无法控制终结器何时运行。

        9
  •  1
  •   Alexander Kahoun    17 年前

    Finalize无法访问托管对象,因此应在Dispose中处理托管对象。这两者之间的区别在于,应使用Dispose for Managed和Finalize for Unmanaged。析构函数应该调用Dispose,以便正确地清除内存。请看以下文章:

    Code Project - IDisposable: What Your Mother Never Told You About Resource Deallocation Gil Fink - Memory Leak And The IDisposable Pattern

    推荐文章