簡體   English   中英

是否可以在程序退出時強制 C# 終結器在 .NET 核心中運行?

[英]Is it possible to force C# finalizers be run in .NET Core on program exit?

我有一個 .NET Core C# class 包裝了一個非托管指針,它應該在程序退出時與其他資源清理一起被釋放。 但是,沒有調用析構函數。 我在調試和發布模式下都試過了。 我看到 .NET Core 顯然不能保證會運行析構函數,那么推薦的解決方法是什么? IMO 垃圾收集的主要目的是避免讓開發人員跟蹤引用,所以我覺得這種行為令人驚訝,至少可以這么說。

來自 MSDN :在 .NET 框架應用程序中(但不在 .NET 核心應用程序中) ,程序退出時也會調用終結器。

public Demo { 
  IntPtr _ptr;

  public Demo() 
  { 
    Console.WriteLine("Constructor");
    _ptr = /* P-invoke external function */ 

  ~Demo 
  {
    Console.WriteLine("Destructor");
    /*P-invoke ptr deletion */
  }
}

public static void Main() 
{ 
  Demo demo = new Demo();
  demo = null;
  GC.Collect();
}

程序 output:

Constructor
<...>\Test.exe (process 7968) exited with code 0.

需要進行更多更改以提高調用終結器的可能性。

順便說一句, Finalizer 永遠不能保證被調用 如果要保證資源釋放,請在應用/方法/代碼塊退出之前實現IDisposable並調用Dispose() 此外,為了確保在退出代碼塊之前調用Dispose() (即使應用程序崩潰,FailFast 和 StackOverflow 除外),請使用try-finallyusing語句。

這是一個可以玩的例子。

public class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("[main] Constructing");
        MyDisposable m = new MyDisposable(0);
        MyMethod(1);
        Console.WriteLine("[main] Disposing [object 0]");
        m.Dispose();
        Console.WriteLine("[main] GC Collecting");
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine("[main] Done");
        Console.ReadKey();
    }

    private static void MyMethod(int i)
    {
        new MyDisposable(i);
    }
}

public class MyDisposable : IDisposable
{
    private int _id;

    public MyDisposable(int id)
    {
        _id = id;
        Console.WriteLine($"[object {_id}] Constructed");
    }

    private bool disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                Console.WriteLine($"[object {_id}] Disposing by Dispose()");
            }
            else
            {
                Console.WriteLine($"[object {_id}] Disposing by ~Finalizer");
            }
            Console.WriteLine($"[object {_id}] Disposed");
            disposed = true;
        }
        else
            Console.WriteLine($"[object {_id}] Already disposed!");
    }

    ~MyDisposable()
    {
        Dispose(false);
    }
}

Output

[main] Constructing
[object 0] Constructed
[object 1] Constructed
[main] Disposing [object 0]
[object 0] Disposing by Dispose()
[object 0] Disposed
[main] GC Collecting
[object 1] Disposing by ~Finalizer
[object 1] Disposed
[main] Done

一些閱讀: 使用實現 IDisposable 的對象

官方清理非托管資源狀態:

如果您的類型使用非托管資源,您應該執行以下操作:

實施處置模式。 (...)

如果您的類型的使用者忘記調用 Dispose,請提供一種釋放非托管資源的方法。 有兩種方法可以做到這一點:

  • 使用安全句柄來包裝您的非托管資源。 這是推薦的技術。 安全句柄派生自 System.Runtime.InteropServices.SafeHandle 抽象 class 並包括一個健壯的 Finalize 方法。 使用安全句柄時,只需實現 IDisposable 接口並在 IDisposable.Dispose 實現中調用安全句柄的 Dispose 方法。 如果未調用其 Dispose 方法,則垃圾收集器會自動調用安全句柄的終結器。

(...)

實現一個 Dispose 方法包含:

  • '實現使用安全句柄的基本 class 的處置模式的一般模式';
  • '實現覆蓋Object.Finalize的基礎 class 的處置模式的一般模式

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM