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

使用析构函数/决赛者是否昂贵?

  •  2
  • Patrick  · 技术社区  · 14 年前

    我正忙于对非确定性破坏感到困惑。在对另一个人的回答中 question 我得到的建议是,析构函数/终结器(我认为在C中是相同的,即名为~classname()的函数)是昂贵的,不需要。但看着 this 示例使用了一个析构函数,从注释中可以看出它可能很重要。有人对这一切是如何结合在一起有一些建议,我应该从代码中删除析构函数吗?

    再次感谢。

    3 回复  |  直到 14 年前
        1
  •  3
  •   Jon Skeet    14 年前

    只有在您绝对 在某个时刻运行一些清理,不管它是否显式执行。在这种情况下,无论如何,您都应该有一种明确的及时进行清理的方式,这应该抑制最终确定,这样“好的”客户就不会看到任何性能损失。

    如果您对非托管资源有直接的句柄,那么通常只需要一个终结器-如果您对 另一个 具有资源句柄的类(例如 FileStream )然后您应该把它留给另一个类来拥有一个终结器。

    随着 SafeHandle 在.NET 2.0中,值得编写自己的终结器的情况是 very rare indeed .

    终结器的性能损失在于,它们使对象的寿命比需要的时间长:在第一个GC周期中,如果它们被认为符合收集条件,它们将被放入终结器队列,并像任何其他在GC周期中生存的对象一样,被提升到下一代。然后,终结器将在另一个线程中运行(在某个点),并且仅 然后 他们真的有资格被收缴吗?因此,他们没有(比如)在第一个Gen1系列中被收集,而是活在过去,直到下一个。 GEN2 收集,可能会很晚。

        2
  •  1
  •   Vladimir Ivanov    14 年前

    通常,实现一个析构函数在on case中很有用:当不能保证时,客户机代码将正确地关闭所有资源(文件流、数据库连接等)。因此,如果客户机代码不能做到这一点,您将得到代码,它将关闭它,这比只打开资源要好。

        3
  •  1
  •   Henk Holterman    14 年前

    当您直接处理非托管资源时,只需要完整的一次性模式。然后由您的调用代码来确保析构函数(几乎)从未被使用过。

    当处理托管资源(=非托管资源的间接所有权)时,析构函数是无用的:

    class FileWrapper
    {
        private FileStream fs;  // managed resource
    
        ~FileWrapper()
        {
             if (fs != null) 
               fs.Dispose();   // fs is already on the GC finalizer queue
        }
    }
    

    每当gc收集一个filewrapper对象时,就可以确定fs对象在同一批中。因此,对fs.dispose()的调用是无用的,只测试filestream.dispose()的正确(允许多次调用)行为。

    这里唯一有用的析构函数是filestream中的析构函数。

    推荐文章