首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在终结器中调用GC.SuppressFinalize是否无害?

在终结器中调用GC.SuppressFinalize是否无害?
EN

Stack Overflow用户
提问于 2019-09-21 22:48:55
回答 1查看 175关注 0票数 2

因为finalizer/IDisposable和所谓的"IDisposable模式“主题往往会产生大量的姿态、崇敬和激进的观点(不是--分别是这里这里这里等等),所以我真的不太愿意问这个问题。为了抢先那些陈腐的辩论,我坚持一个非常简单的问题,在StackOverflow上似乎没有一个简明的答案.

一旦对象的终结器开始执行,是否调用GC.SuppressFinalize(this)为空?更具体或更有用(当然),从终结器本身调用GC.SuppressFinalize(this)是无害的吗?(再说一次,我们在这里没有讨论任何“为什么”)

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

EN

回答 1

Stack Overflow用户

发布于 2019-09-22 01:28:16

当然,最好完全避免使用终结器,并按照现代成语的要求使用SafeHandle。然后所有关于终结器的东西都变得完全没有意义了。

尽管如此,尽管这样做是明智的,但是从终结器中调用GC.SuppressFinalize()是完全安全的。方法的文档描述了该方法的功能:

此方法在obj的对象标头中设置位,运行库在调用终结器时对其进行检查。

运行时也可以在GC操作期间检查此位,即在找到不可访问的对象时,该对象的终结器将被放入终结器队列中。如果在这一点上设置了终结器,那么终结器甚至不会出现在队列中。

稍后,在调用终结器本身之前再次检查它,如果发现其他对象的终结器最后处理它,即使将该对象的终结器放在终结队列中,也可以避免对象的终结。

这两个检查都是在调用终结器之前进行的。一旦调用终结器,对象中的位就没有用途了。设置它是无害的,但什么也做不到。

顺便提一下:请注意,过去的.NET实现使用了FinalizerFReachable队列。当一个对象被创建时,如果它有终结器,它将被移动到Finalizer队列中。一旦无法到达该对象,它将被移动到FReachable队列中,以便稍后完成。调用SuppressFinalize()将从Finalizer队列中移除对象。当终结器运行时,对象不再在这个队列中,因此SuppressFinalize()调用将是一个NOP,类似地无害。

现在,尽管如此,您的问题是广泛的:"…是否存在任何坏的、不需要的或其他有形的正确性或性能影响?“其中很大一部分是在旁观者的眼中。我认为调用GC.SuppressFinalize()的终结器是不正确的。因此,对我来说,这将是一个“有形的正确性效应”。我还发现,偏离已发布、公认的标准模式的代码是“不受欢迎的”。如果问题中没有更具体的标准加以限制,问题的这一部分的答案可能是“是”、“否”、“有时”等等。

事实上,你有一个重复的问题,但没有人屈尊回答它:从终结器中调用GC.SuppressFinalize()。不过,我确实找到了关于这一点的评论,特别是Eric Lippert的贡献:

您的假设是,对SuppressFinalize的不必要调用是计划中的错误。这不是问题;问题是如何处理终结器线程上的托管资源。回想一下,终结器运行在自己的线程上,托管资源可以是线程关联的,现在开始想象可能导致的恐怖。此外:终结器按任意顺序运行。在终结器线程上释放的托管对象可能已经完成;现在您可能在一个对象上运行两次终结逻辑;它对该场景是否健壮?- Eric Lippert Mar 31 '16,21:58 1 编写一个正确的终结器是非常困难的,我建议您不要尝试,理想情况下,但是一定要等到您更好地理解模式。如果你还没有被吓到,我的系列文章可能会让你更害怕:ericlippert.com/2015/05/18/… - Eric Lippert Mar 31 '16,21:59。 … @Tom:问题是“我使用了完全错误的处理模式,这是我所做的错误的一部分吗?”不,整件事从第一句起就错了。您不使用Dispose来处理托管资源,当然也不会为此使用终结器。这就是问题所在。从终结器调用SuppressFinalize本身有什么问题吗?好吧,它会起作用的,但是不应该有这样一种情况,在这种情况下,这是正确的,所以它是否起作用应该是无关紧要的。-埃里克·利佩特·7月7日14时17分 @汤姆:还有,你为什么一开始就叫SuppressFinalize?仅仅是因为它是一个性能优化。但是,在什么情况下,从终结器线程调用它是一个优化?只有当您未能从主线程进行优化时!那就是进行优化的地方!-埃里克·利珀特·7月7日14:24

IMHO,这些评论把主要问题带到了一个很好的问题:询问从终结器调用SuppressFinalize()是否安全是一个错误的问题。如果你不得不问这个问题,代码已经错了,问题的答案可能没有那么重要。正确的方法是修复代码,这样您就不必问这个问题了。

最后,虽然不是完全相同的问题,但我认为还值得指出的是,通常在SuppressFinalize()方法末尾调用Dispose()的指导可能是不正确的。如果被调用,则应该在Dispose()方法的开头调用它。请参阅把GC.SuppressFinalize放在哪里要小心

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58044679

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档