C#我的析构函数没有被调用? [英] c# my destructor isn't being called?

查看:1177
本文介绍了C#我的析构函数没有被调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个简单的代码,试图调用析构函数,但是我不能调用它:(

I have this simple code and trying to call the destructor but I can't call it :(

我知道GarbageCollector会在必要时运行,因此我使用了GC.WaitForPendingFinalizers();.但它也不起作用.

I know that GarbageCollector runs when it's necessary, so I used GC.WaitForPendingFinalizers(); but it didn't work either.

这是我的代码:

class Program
    {
        static void Main(string[] args)
        {
            Calculator calculator = new Calculator();
            Console.WriteLine("{0} / {1} = {2}", 120, 15, calculator.Divide(120, 15)

            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine("Program finishing");                           
        }

  }

class Calculator
    {

        // Constructor
        public Calculator()
        {
            Console.WriteLine("Calculator being created");
        }

        // Public Divide method
        public int Divide(int first, int second)
        {
            return first / second;
        }

        // Destructor
        ~Calculator()
        {
            Console.WriteLine("Destructor is called");

        }

    }

这是我的输出:

正在创建计算器

Calculator being created

120/15 = 8

120 / 15 = 8

程序完成

我做错了什么?为什么我看不到调用了析构函数"?

What am I doing wrong? Why can't I see "Destructor is called" ?

推荐答案

局部变量生存期是指控件内部激活的生存期.声明它的局部变量范围.因此,您的本地用户还活着,直到main结束.仅此一项就足以解释为什么不收集它,但是这里有一些微妙之处,我们应该更深入地探讨.

The lifetime of a local variable is the lifetime of the activation of control within the local variable scope that declares it. So your local is alive until the end of main. That alone is sufficient to explain why it is not collected, but there are subtleties here that we should explore in more depth.

可以通过多种机制来延长生存期,包括通过lambda捕获外部变量,迭代器块,异步方法等.

The lifetime may be extended by a variety of mechanisms, including capturing outer variables by a lambda, iterator blocks, asynchronous methods, and so on.

在抖动可以证明这样做不会影响单线程控制流的情况下,可以缩短寿命. (您可以使用KeepAlive确保在必须避免这种情况下不会发生这种缩短.)

The lifetime is permitted to be shortened in cases where the jitter can prove that doing so has no effect on the single-threaded flow of control. (You can use KeepAlive to ensure this shortening does not happen in cases where you must avoid it.)

在您的情况下,允许运行时 ,注意不再从本地读取该本地,将其早期标记为无效,从而孤立了对该对象的引用,然后对该对象的引用进行收集并最终确定.不需要这样做,显然,就您而言,不是那样的.

In your case, the runtime is permitted to notice that the local is never read from again, mark it as dead early, and thereby orphaning the reference to the object, which would then be collected and finalized. It is not required to do so, and apparently, in your case, does not.

正如另一个答案正确指出的那样:如果GC检测到调试器正在运行,它将故意抑制此优化,因为当您在其中检查包含对它的引用的变量时,收集对象的用户体验很差.调试器!

As another answer correctly notes: the GC will deliberately suppress this optimization if it detects that a debugger is running, because it is a bad user experience for an object to be collected while you are examining a variable containing a reference to it in the debugger!

让我们考虑一下我有关缩短寿命的陈述的含义,因为我认为您可能还没有完全理解这些含义.

Let's consider the implications of my statements about shortened lifetimes, because I think you may not have fully grasped those implications.

  • 允许运行时注意 ctor从不访问此.

允许运行时注意 divide永远不会访问此.

允许运行时注意,因此从不实际读取和使用本地

The runtime is permitted to notice that therefore the local is never actually read from and used

因此,该对象在生命周期的任何时候都不得在GC中植根.

这意味着允许垃圾收集器在构造函数之前运行终结器.

GC和终结器在各自的线程上运行,请记住;操作系统可以在任何时候挂起主线程并切换到gc和finalizer线程,包括在分配器运行之后但在控制权传递给构造函数之前.

The GC and finalizer runs on their own threads, remember; the operating system could suspend the main thread and switch to the gc and finalizer threads at any point, including after the allocator runs but before control passes to the constructor.

在您所写的场景中绝对可以发生疯狂的事情;终结器未运行是您最少的问题!这是可以运行的时候,令人感到恐惧.

Absolutely crazy things are permitted to happen in scenarios like the one you wrote; the finalizer not running is the least of your problems! It is when it could run that is scary.

如果您现在还不清楚这一事实,那么您无需编写终结器.编写正确的终结器是C#中最难的事情之一.如果您不是CLR垃圾收集器语义的所有详细信息的专家,则不应编写终结器.

If that fact was not immediately clear to you, then you have no business writing a finalizer. Writing a correct finalizer is one of the hardest things to do in C#. If you are not an expert on all the fine details of the CLR garbage collector semantics, you should not be writing a finalizer.

有关如何编写终结器的更多想法,请参阅我关于该主题的系列文章,从这里开始:

For more thoughts on how writing a finalizer is difficult, see my series of articles on the subject, which begins here:

https://ericlippert .com/2015/05/18/when-everything-you-know-is-wrong-part-one/

这篇关于C#我的析构函数没有被调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆