析构,配置和完成方法之间的区别


74

我正在研究垃圾收集器在C#中的工作方式。我很困惑在使用DestructorDisposeFinalize方法。

根据我的研究和理解,在我的类中具有Destructor方法将告诉垃圾收集器以destructor方法中提到的方式执行垃圾收集,而该方法不能在类的实例上显式调用。

Dispose方法旨在为用户提供控制垃圾收集的功能。该Finalize方法释放类使用的资源,但不释放对象本身。

我不确定我是否理解正确。请澄清怀疑。欢迎任何其他链接或指南。

Answers:


66

析构函数隐式调用Finalize方法,它们在技术上是相同的。处置可用于实现IDisposable接口的对象。

您可能会看到:析构函数C#-MSDN

析构函数在对象的基类上隐式调用Finalize。

来自同一链接的示例:

class Car
{
    ~Car()  // destructor
    {
        // cleanup statements...
    }
}

析构函数的代码隐式转换为以下代码:

protected override void Finalize()
{
    try
    {
        // Cleanup statements...
    }
    finally
    {
        base.Finalize();
    }
}

您对Destructor的理解是正确的:

MSDN

程序员时,因为这是由垃圾收集器确定的析构函数被称为无法控制。垃圾收集器检查应用程序不再使用的对象。如果认为某个对象符合销毁条件,它将调用析构函数(如果有)并回收用于存储该对象的内存。程序退出时也会调用析构函数。可以通过调用Collect强制进行垃圾回收,但是在大多数情况下,应避免这种情况,因为这可能会导致性能问题。


如何通过调用强制垃圾回收Collect()可能会导致性能问题?
破坏者

50

用C#术语来说,析构函数和终结器基本上是可互换的概念,并应在收集类型(例如外部句柄)时用于释放非托管资源。这是非常罕见的,你需要写一个终结。

这样做的问题是GC是不确定的,因此该Dispose()方法(通过IDisposable)可以支持确定性清除。这与垃圾回收无关,并且允许调用者更快地释放任何资源。它也适用于托管资源(除了非托管资源之外),例如,如果您具有封装(例如)数据库连接的类型,则可能还希望处置该类型以释放连接。


因此,我的感觉是Destructor方法仅应包含必须在销毁其之前执行的代码,而Finalize方法此后大部分将继承自超类。
Victor Mukherjee

3
再次@VictorMukherjee,它们(析构函数和终结函数)可以互换。它是销毁之前Dispose()会被调用的,但不会被称为析构函数或终结器
Marc Gravell

嗨,马克,认为GC主要是确定性的,只是规则并不为人所知吗?我不是专家,总是在学习,我想知道您的评论是在finalizers还是dispose的背景下概括地讲吗?还是不确定性很大(尽管这可能是另一天的另一个问题)?
Alex KeySmith

1
@AlexKeySmith我不得不说后者,因为它受时序,CPU活动以及外部因素(例如外部存储器)的控制
Marc Gravell

谢谢马克,这非常有用。嗯,即使基础规则是确定性的,但它仍受应用程序控制范围之外的支配,实际上是不确定性的。感谢您的见解!
Alex KeySmith
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.