析构函数、dispose 和 finalize 方法的区别

Posted

技术标签:

【中文标题】析构函数、dispose 和 finalize 方法的区别【英文标题】:Difference between destructor, dispose and finalize method 【发布时间】:2012-12-08 22:15:11 【问题描述】:

我正在研究垃圾收集器在 c# 中的工作原理。我对DestructorDisposeFinalize 方法的使用感到困惑。

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

Dispose 方法旨在让用户控制垃圾回收。 Finalize 方法释放类使用的资源,但不释放对象本身。

我不确定我是否理解正确。请澄清疑惑。欢迎任何进一步的链接或指南。

【问题讨论】:

【参考方案1】:

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

您可能会看到:Destructors C# - MSDN

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

来自同一链接的示例:

class Car

    ~Car()  // destructor
    
        // cleanup statements...
    

析构函数的代码被隐式翻译成如下代码:

protected override void Finalize()

    try
    
        // Cleanup statements...
    
    finally
    
        base.Finalize();
    

你对析构函数的理解是对的:

来自MSDN

程序员无法控制何时调用析构函数 因为这是由垃圾收集器决定的。垃圾 收集器检查不再被 应用。如果它认为一个对象有资格销毁,它 调用析构函数(如果有)并回收用于存储的内存 物体。程序退出时也会调用析构函数。它是 可以通过调用 Collect 来强制进行垃圾收集,但大多数 时间,这应该避免,因为它可能会创建性能 问题。

【讨论】:

如何通过调用Collect() 强制垃圾回收可能会产生性能问题? @Destructor,GC 的标记阶段使用 DFS,它相对于应用程序中的对象总数具有线性时间和空间复杂性。所以,最好还是让 GC 来决定什么时候使用这么多资源,不要自己去利用。【参考方案2】:

在 C# 术语中,析构函数和终结器基本上是可互换的概念,应该用于在收集类型时释放 非托管 资源,例如外部句柄。您需要编写终结器非常很少见。

问题在于 GC 是非确定性的,因此Dispose() 方法(通过IDisposable)可以支持确定性 清理。这与垃圾回收无关,并允许调用者尽快释放任何资源。它也适用于托管资源(除了非托管),例如,如果你有一个封装(比如)数据库连接的类型,你可能想要处理也释放连接的类型。

【讨论】:

所以我觉得Destructor方法应该只包含在其销毁之前必须执行的代码,Finalize方法将主要从超类继承。 @VictorMukherjee 再次,它们(析构函数和终结器)是可以互换的。 Dispose() 将被称为 before 销毁,但它既不称为析构函数也不是终结器 嗨,Marc,认为 GC 主要是确定性的,只是规则不为人所知,是否正确?我不是专家,一直在学习,我想知道您的评论是否只是在终结者与处置的背景下泛泛而谈?还是它非常不确定(尽管这可能是另一天的另一个问题)? @AlexKeySmith 我不得不说后者,因为它受时间、CPU 活动和外部因素(如外部内存)控制 谢谢 Marc,这很有用;啊,所以即使基本规则是确定性的,它也受到应用程序控制之外的许多因素的控制,它实际上是非确定性的。感谢您的洞察力!

以上是关于析构函数、dispose 和 finalize 方法的区别的主要内容,如果未能解决你的问题,请参考以下文章

2018-7-6-随笔-析构函数

C#-C# Dispose模式详细分析

C#学习笔记---Dispose(),Finalize(),SuppressFinalize

java finalize学习

safehandle 和析构函数

在 C# 中,类中的析构函数和 Finalize 方法有啥区别?