简体   繁体   English

是否可以在程序退出时强制 C# 终结器在 .NET 核心中运行?

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

I have a .NET Core C# class that wraps an unmanaged pointer and it should be freed on program exit along with other resource cleanup.我有一个 .NET Core C# class 包装了一个非托管指针,它应该在程序退出时与其他资源清理一起被释放。 However, the destructor is not being called.但是,没有调用析构函数。 I have tried in both Debug and Release mode.我在调试和发布模式下都试过了。 I see that .NET Core apparently doesn't guarantee that destructors will be run, so what is a recommended workaround?我看到 .NET Core 显然不能保证会运行析构函数,那么推荐的解决方法是什么? IMO the main point of garbage collection is to avoid having the developer track references, so I find this behavior surprising, to say the least. IMO 垃圾收集的主要目的是避免让开发人员跟踪引用,所以我觉得这种行为令人惊讶,至少可以这么说。

From MSDN : In .NET Framework applications (but not in .NET Core applications) , finalizers are also called when the program exits. 来自 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();
}

Program output:程序 output:

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

More changes are needed to improve the likelihood that the finalizer will be called.需要进行更多更改以提高调用终结器的可能性。

Btw, Finalizer is never guaranteed to be called .顺便说一句, Finalizer 永远不能保证被调用 If you want to gurantee the resources release, implement IDisposable and call Dispose() before the app/method/code block exit.如果要保证资源释放,请在应用/方法/代码块退出之前实现IDisposable并调用Dispose() Additionally to make Dispose() guaranteed to call (even if app crashes, except FailFast and StackOverflow) before exiting the code block, use try-finally or using statements.此外,为了确保在退出代码块之前调用Dispose() (即使应用程序崩溃,FailFast 和 StackOverflow 除外),请使用try-finallyusing语句。

Here's an example to play with.这是一个可以玩的例子。

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 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

Some read: Using objects that implement IDisposable .一些阅读: 使用实现 IDisposable 的对象

The official Cleaning up unmanaged resources states:官方清理非托管资源状态:

If your types use unmanaged resources, you should do the following:如果您的类型使用非托管资源,您应该执行以下操作:

Implement the dispose pattern.实施处置模式。 (...) (...)

In the event that a consumer of your type forgets to call Dispose, provide a way for your unmanaged resources to be released.如果您的类型的使用者忘记调用 Dispose,请提供一种释放非托管资源的方法。 There are two ways to do this:有两种方法可以做到这一点:

  • Use a safe handle to wrap your unmanaged resource.使用安全句柄来包装您的非托管资源。 This is the recommended technique.这是推荐的技术。 Safe handles are derived from the System.Runtime.InteropServices.SafeHandle abstract class and include a robust Finalize method.安全句柄派生自 System.Runtime.InteropServices.SafeHandle 抽象 class 并包括一个健壮的 Finalize 方法。 When you use a safe handle, you simply implement the IDisposable interface and call your safe handle's Dispose method in your IDisposable.Dispose implementation.使用安全句柄时,只需实现 IDisposable 接口并在 IDisposable.Dispose 实现中调用安全句柄的 Dispose 方法。 The safe handle's finalizer is called automatically by the garbage collector if its Dispose method is not called.如果未调用其 Dispose 方法,则垃圾收集器会自动调用安全句柄的终结器。

(...) (...)

Implement a Dispose method contains: 实现一个 Dispose 方法包含:

  • ' the general pattern for implementing the dispose pattern for a base class that uses a safe handle '; '实现使用安全句柄的基本 class 的处置模式的一般模式'; and
  • ' the general pattern for implementing the dispose pattern for a base class that overrides Object.Finalize '. '实现覆盖Object.Finalize的基础 class 的处置模式的一般模式

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM