【问题标题】:difference between destructor and garbage collector析构函数和垃圾收集器的区别
【发布时间】:2012-03-16 08:06:08
【问题描述】:

我想知道析构函数和垃圾收集器有什么区别,析构函数用于在应用程序生命周期结束时处理所有未使用的对象,垃圾收集器的使用也是如此,垃圾收集器可以手动在应用程序结束时调用或完成,与析构函数相同,都是可选的,用于处理未引用的对象,谁能指出我的确切区别是什么

【问题讨论】:

  • .Net(像大多数垃圾收集语言一样)没有析构函数。在 C++/CLI 中,它们是使用终结器伪造的。
  • @Billy 在 C# 语言规范中使用了术语“终结器”和“析构函数”来指代同一事物。
  • @MarcGravell:这很奇怪;它们确实具有完全不同的语义。一个概念是确定性地运行的;另一个不是。不过,我在 CLR 级别上的思考要多于 C# 级别;毕竟问题是 .Net 而不是 C#,就 CLR 而言,析构函数不存在。
  • @Billy 确实如此,这很可能就是术语随时间变化的原因。但事实仍然存在:这些术语因此变得有点但可以互换。
  • @MarcGravell:至少在 C# 圈子里 :) (如果我说终结器和析构函数对于 C++/CLI 人来说是可以互换的,我可能会被枪杀)

标签: .net garbage-collection destructor


【解决方案1】:

析构函数是一个特殊的成员函数,在对象被销毁时调用。它是类运行的最后一个方法。

垃圾收集器是框架的一部分,自动管理内存,并且非确定性地收集未引用的对象以避免内存泄漏。

【讨论】:

  • 析构函数生成的Finalize 方法在 GC 发现一个对象时被调用.它通常是在类对象上运行的最后一个方法,但有可能在终结器完成之前(甚至可能在它开始之前!)的任何时候创建和存储对该对象的根强引用,在这种情况下,对象可能继续无限期地存在。
【解决方案2】:

垃圾收集器是 .NET 环境的一部分,它跟踪对象并确保在不再需要对象时将其从内存中删除。

析构函数是类设计的一部分。它与构造函数相反。当你声明它时,GC 会在它销毁一个对象时调用它。

Here is the MSDN documentation.

【讨论】:

    【解决方案3】:

    垃圾收集器和终结器/析构函数是内在联系的——但是,大多数对象不需要(也没有)析构函数。它们实际上在托管代码中非常少见,通常用于确保释放非托管资源。如果一个对象有一个析构器/终结器,垃圾收集器会在收集的同时调用它(可能在下一次传递中)。垃圾收集是非确定性的 - 它会在它发生时发生 - 通常与内存压力有关。

    然而,更常见的是 IDisposable。这允许现在(而不是下次发生 GC 时)释放资源的更可预测的模式。通常,具有终结器的类是 IDisposable,其中 Dispose() 实现禁用析构函数(如果我们已经清理过,则不需要它)。请注意,Dispose() 与垃圾回收无关,但通过“using”语句提供语言支持。

    IDisposable 比终结器更常见。您有责任确保处置任何 IDisposable。附加说明:处理某些东西不会导致对象被收集;这只能由 GC 根据 GC 选择的任何时间表完成。处置,而是释放相关资源。例如,您不希望文件在 GC 发生之前被锁定打开;此处的 Dispose() 解锁文件(通过释放 OS 文件句柄)。

    【讨论】:

    • 好吧,让我看看我是否明白了这个概念,GC用于检查是否需要对对象进行任何处理,如果需要,它将调用析构函数,GC无法自行销毁任何东西,而另一方面, Desctructor 将在类结束时销毁对象,并且析构函数无法检查内存问题,它只是在最后销毁所有内容。我说的对吗?
    • @Abbas 多个“不完全”恐怕。首先,避免使用“dispose”这个词——如果IDisposable,GC 永远不会“dispose”,所以远离这个词是值得的。现在;一旦每个对象不再可访问,GC 负责回收每个对象使用的托管堆上的内存。它非常能摧毁任何东西。但是,如果有一个析构函数/终结器(并且没有为该对象显式禁用),那么 GC 将调用析构函数/终结器以允许该类有机会清理任何非托管资源。
    • 你说“它非常可以破坏任何东西”,而且析构函数最终可以破坏所有东西,在这种情况下两者之间有什么区别,但是 MSDN 说“当对象有资格销毁,垃圾收集器运行对象的Finalize方法。”,这意味着GC无法释放内存,它必须调用析构函数来释放内存:这里链接msdn.microsoft.com/en-us/library/66x5fx1b.aspx
    • @Abbas 析构函数无法释放 托管 内存 - GC 会处理它; CLI 中终结器/析构函数的工作是释放 非托管 资源 - 操作系统句柄、非托管内存段等。
    • 所以不能GC,释放一些对象占用的堆上的内存,该对象没有在任何地方引用,托管和非托管内存有什么区别。
    【解决方案4】:

    垃圾收集器的主要工作方式是将它可以找到的所有对象复制到 RAM 的新部分,然后对旧区域进行核对;它既不知道也不关心是否留下了 5 个或 500,000 个对象。请注意,除了查找所有由实时强引用引用的对象外,垃圾收集器还可以查找其他一些对象,包括覆盖 Finalize 的对象、用作监视器锁的对象、WeakReference 对象所针对的对象等。从轨道上对旧区域进行核打击,垃圾收集器必须处理它所知道的任何“特殊”物体,这些物体可能仍然存在。

    除此之外,垃圾收集器有一个已注册终结器的所有对象的列表;它将检查该列表中的所有对象以查看它们是否已被复制到新的内存区域。如果发现任何尚未出现的对象,它们将从具有已注册终结器的对象列表中删除,并添加到应尽快运行 Finalize 方法的对象列表中。一旦对所有具有注册终结器的对象完成此操作,需要立即终结的对象列表中的任何对象以及这些对象持有引用的任何对象都将被复制到新区域。

    【讨论】:

      猜你喜欢
      • 2012-03-16
      • 2015-03-14
      • 1970-01-01
      • 2012-12-23
      • 2012-03-21
      • 1970-01-01
      • 2015-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多