本文介绍了在终结器中调用GC.SuppressFinalize是否无害?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因为finalizer/IDisposable和所谓的"IDisposable模式"主题往往会带来很多姿态,崇高和好战的观点(不是-分别是,,等),我真的很想问这个问题.为了避免那些陈旧的辩论,我要提出一个非常简单的问题,该问题似乎在StackOverflow上没有简明的答案...

对象的终结器开始执行后,是否正在调用GC.SuppressFinalize(this)空虚?更具体地说,或者更有用(当然),从终结器自身内部调用GC.SuppressFinalize(this)是否无害? (再次,我们在这里不讨论任何为什么")

换句话说,除了调用API以及在对象标头中正确设置标志的开销之外,是否还有任何不良的,不需要的或其他有形的正确性或性能影响?

解决方案

当然,最好完全避免使用终结器,并使用SafeHandle,这是现代习语所规定的.然后,所有关于终结器的东西都变得毫无意义.

也就是说,尽管这样做很明智,但是从终结器中调用GC.SuppressFinalize()是绝对安全的. 方法的文档描述该方法的作用:

运行时实际上也可以在GC操作期间检查此位,这是在发现对象不可达时,该对象的终结器将放入终结器队列中.如果已将其设置为该值,则终结器甚至不会在队列中结束.

稍后,在调用终结器本身之前再次检查它,也可以避免对象的终结,即使事实证明,即使该对象的终结器已放入终结队列中,其他对象的终结器也将其处置掉.

这两项检查均在调用终结器之前进行.调用终结器后,对象中的位将无用.设置它是无害的,但不会完成任何事情.

顺便说一句:请注意,.NET的过去实现使用FinalizerFReachable队列.创建对象时,如果它具有终结器,则将其移至Finalizer队列.一旦对象不可访问,它将被移到FReachable队列中以便以后完成.调用SuppressFinalize()将从Finalizer队列中删除该对象.终结器运行时,对象不再在此队列中,因此SuppressFinalize()调用将是NOP,同样无害.

现在,这就是说,您的问题很广泛:…是否存在任何不良的,不需要的或其他有形的正确性或性能影响?" .这在旁​​观者的眼中是很多.我认为调用GC.SuppressFinalize()的终结器是不正确的.因此,这对我来说将是有形的正确性效应".我还发现偏离已发布的公认标准模式的代码是有害的".如果问题中没有更具体的标准来约束它,那么该部分问题的答案可能是是",否",有时"等等.

实际上您有一个重复的问题,但没人愿意回答:从终结器中调用GC.SuppressFinalize().不过,我确实找到了评论的线索,尤其是埃里克·利珀特(Eric Lippert)的贡献:

恕我直言,这些评论将主要问题引向了一个很好的问题:从终结器中调用SuppressFinalize()是否安全是一个错误的问题.如果您不得不问这个问题,那么代码已经是错误的,并且该问题的答案可能并没有那么重要.正确的方法是修复代码,这样您就不必再问这个问题了.

最后,虽然问题不完全相同,但我认为也有必要指出,在Dispose()方法末尾调用SuppressFinalize()的通常指导可能是错误的.如果被调用,则应在Dispose()方法的开始处调用它.参见小心放置GC .SuppressFinalize

Because the finalizer/IDisposable and so-called "IDisposable pattern" topic tends to bring out lots of posturing, pontificating, and militant opinion (not-respectively, here, here, here, and more), I really hesitate to ask this. Hoping to preempt those well-worn debates, I'm keeping to a very simple question which doesn't appear to have a concise answer on StackOverflow...

Is calling GC.SuppressFinalize(this) vacuous once the object's finalizer has begun executing? More specifically or usefully (of course), is it harmless to call GC.SuppressFinalize(this) from within the finalizer itself? (Again, we're not debating any "why" here)

So in other words, beyond the overhead for calling the API and its duly setting a flag in the object header, are there any bad, unwanted, or otherwise tangible correctness or performance effects?

解决方案

Of course, it would be much better to avoid the finalizer altogether, and use SafeHandle, as the modern idiom dictates. Then all of this stuff about finalizers becomes completely moot.

That said, the wisdom of doing so notwithstanding, it is perfectly safe to call GC.SuppressFinalize() from the finalizer. The documentation for the method describes what the method does:

The runtime may actually check this bit during a GC operation as well, which is when on finding an object unreachable, that object's finalizer would be put into the finalizer queue. If it's set at that point, finalizer doesn't even wind up in the queue.

Checking it again later, before calling the finalizer itself, also allows finalization of the object to be avoided, if it turns out that some other object's finalizer wound up disposing it even though the that object's finalizer was put in the finalization queue.

Both of these checks occur before the finalizer is called. Once the finalizer is called, the bit in the object has no purpose. Setting it is harmless, but won't accomplish anything.

As an aside: note that past implementations of .NET used Finalizer and FReachable queues. When an object was created, if it had a finalizer, it would be moved to the Finalizer queue. Once the object was unreachable, it would be moved to the FReachable queue for later finalization. Calling SuppressFinalize() would remove the object from the Finalizer queue. By the time the finalizer runs, the object is no longer in this queue, so the SuppressFinalize() call would be a NOP, similarly harmless.

Now, that said, your question is broad: "…are there any bad, unwanted, or otherwise tangible correctness or performance effects?". Much of that is in the eye of the beholder. I would argue that a finalizer that calls GC.SuppressFinalize() is incorrect. So, that would be a "tangible correctness effect" to me. I also find code that deviates from published, acknowledged standard patterns to be "unwanted". Without more specific criteria in the question to constrain it, the answer to that part of the question could be any of "yes", "no", "sometimes", etc.

There is in fact a duplicate question to yours, but no one's deigned to answer it: Calling GC.SuppressFinalize() from within a finalizer. I do find the thread of comments on point though, especially Eric Lippert's contributions:

IMHO, these comments bring the primary issue to a fine point: asking whether it's safe to call SuppressFinalize() from the finalizer is the wrong question. If you've gotten as far as having to ask that question, the code is already wrong, and the answer to the question is probably not all that relevant. The right approach is to fix the code so you don't have to ask that question.

Finally, while not exactly the same issue, I think it's also worth pointing out that the usual guidance to call SuppressFinalize() at the end of the Dispose() method is probably incorrect. If called, it should be called at the beginning of the Dispose() method. See Be Careful Where You Put GC.SuppressFinalize

这篇关于在终结器中调用GC.SuppressFinalize是否无害?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 22:35