【问题标题】:Destructors in .NET.NET 中的析构函数
【发布时间】:2016-12-19 07:02:29
【问题描述】:

NET 很长一段时间,已经开始学习 C#。我想我几年前可能问过的一件事,得到了答案,但现在完全忘记了,因为它不是我隐含使用的东西,就是析构函数。在我学习 C# 的过程中,我阅读了一篇关于如何在 C# 中创建这些的文章,但它让我感到疑惑。假设我实例化了一个具有另一个类的对象的类。

Class C1
{
  // Do something here
}

Class A
{
  C1 objObjectToClass1 = new C1();
}   

Class Main
{
   A objObjectToClassA = new A();
}

并且我将对象 objObjectToClassA 设置为 null,因为我一直认为它等同于 VB.NET 中的 object = nothing

objObectToClassA = null;

此操作是否也会破坏objObjectToClass1

【问题讨论】:

  • 为什么需要将objObjectToClassA 设置为null,或者使用 Desctructor? GC不会把未使用的对象分拣出来吗?
  • 4 次投票,没有一个解释?伙计们?
  • 明确地将对象设置为 null 并帮助 GC 将对象标记为收集并没有什么问题
  • 真不公平,无缘无故投反对票,完全不公平

标签: c# destructor


【解决方案1】:

不是这样的,不。一个对象将在它符合收集条件后的某个时间被垃圾收集器回收。这可能是在您清除对它的最后一个引用之后,但如果您在某个点之后不再需要该引用,它可能已经在之前。但通常,将存储实例的字段设置为 null 将有助于对象变得不再可访问并被回收。

通常您无法控制 GC 何时回收对象。您可以编写 finalizers,它们是在回收对象之前调用的方法,但如果您能提供帮助,我非常推荐它。如果您需要一种可预测的方式来使对象释放它可能持有的任何资源(C++ 中的析构函数通常会这样做),那么请实现IDisposable interface

class C1 : IDisposable {
  public void Dispose() {
    // Do cleanup here
  }
}

这还使您能够在 using statement 中使用该类的实例,这将在其块的末尾调用 Dispose

using (var c1 = new C1()) {
  // do stuf with c1 here
} // at this point c1.Dispose() is automatically called

【讨论】:

  • 这是否意味着将其设置为 null 将删除任何引用,并且将级联到我设置为 null 的对象中的所有对象。抱歉,我的错误应该更好地措辞我知道它仍然存在,直到 GC 来收集它,但这是我使用 VB.NET 明确告诉 GC 我不再使用这个对象的方法之一
  • “通常你无法控制......” - 从技术上讲,有GC.Collect()。但既然你说的很笼统,我想你是对的。
  • @altaaf.hussein:将字段设置为 null 将删除 one 引用。如果那是唯一剩下的,那么是的,该对象应该有资格被收集。但是有很多方法可以泄漏实例,例如通过不是立即显而易见的事件处理程序、闭包等。所以不,一般而言,将某些内容设置为 null 并不能保证 GC 收集某个对象实例。
  • @Toastgeraet:这是大多数 .NET 开发人员不应该接触的方法 ;-)
  • Skeet 先生在他的answer to another question 中给出了一个很好的例子,说明何时使用 GC.Collect 可能很好。
【解决方案2】:

垃圾收集器知道什么时候不再有对象引用,据我所知,它甚至会销毁只被另一个对象引用的对象。

这意味着如果您取消引用objObjectToClassA(将其设置为null),如果不再引用其中任何一个对象,那么这两个对象都将被销毁。简单地让它超出范围也足够了。

【讨论】:

    【解决方案3】:

    实际上,是的,它也会销毁objectToClass1,但不会立即销毁。在这种情况下,将变量设置为 null 意味着您的应用程序不再使用该对象,因此它可以进行垃圾回收。简单地考虑一下(我敢肯定 GC 比这更聪明),一旦收集了objectToClassA,那么 objectToClass1 将不再被引用并且也会被收集。

    Joey 关于IDisposable 的cmets 绝对值得记住;尽量不要考虑 C# 的终结器,因为您无法控制它们何时运行。使用IDisposable 将为您提供整理资源所需的控制权。

    【讨论】:

    • 除了 .NET 对象不被引用计数;当没有指向根的引用路径时,对象有资格被收集,而不是当它们不再被引用时。
    • 公平评论;我已经删除了引用计数的提及。我真的不认为垃圾收集器的精确工作方式在这里很重要。关键是垃圾收集器决定何时清理,因此您无法控制终结器何时运行......
    【解决方案4】:

    Destroy 是错误的词,C#(据我所知)没有 C++ 意义上的析构函数。垃圾收集器收集/“销毁”不再使用的对象。

    如果没有保留对objObjectToClass1的其他引用,如果将objObectToClassA设置为null,也可以收集objObjectToClass1

    【讨论】:

    • 不是 c++ 意义上的,但它确实有一个终结器形式的析构函数,它有助于 GC 确定拍摄对象的收集,否则这是不确定的,或者我们甚至可以使用 Dispose 来完全抑制终结
    • 这就是为什么我写的不是 C++ 意义上的。终结器提供了一些类似的功能,但与 C++ 析构函数非常不同。而且终结器也不是确定性的。
    • 这不是苹果与苹果的比较,因为 C++ 中没有用于内存管理的 GC,所以不是一个公平的比较。与 Java 的比较将更加相关。顺便说一句,我没有投反对票。
    • 由于 OP 使用了“析构函数”这个词,因此他似乎很可能来自 C/C++,并且似乎值得指出不同之处。为什么要将它与 Java 进行比较?
    猜你喜欢
    • 1970-01-01
    • 2016-09-09
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    • 2021-11-04
    • 2013-03-17
    • 2010-11-29
    • 1970-01-01
    相关资源
    最近更新 更多