GC.SuppressFinalize是否有保证? [英] Is GC.SuppressFinalize guaranteed?

查看:103
本文介绍了GC.SuppressFinalize是否有保证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在实践中观察到 GC.SuppressFinalize 并不总是禁止对终结器的调用。可能是终结者被称为无关紧要的。因此,我想知道 GC.SuppressFinalize 是否具有请求的性质而不是系统保证 p>




更多信息

如果需要,可以帮助为问题提供更多的上下文。



GC.SuppressFinalize 文档摘要确实是一个请求:


请求系统不要为指定对象调用
终结器。


我想知道这是一个偶然使用的单词还是真正用于描述运行时行为。



我已经用下面的 SingletonScope 类来自 Schnell 项目,这是基于一个 Ian Griffiths的原创想法,除了它更广义化。这个想法是在调试版本中检测 Dispose 方法是否被调用。如果不是,终结者最终会踢,并且可以发出警告。如果调用 Dispose ,那么 GC.SuppressFinalize 应阻止终结器触发。不幸的是,这些警告似乎无论如何都会触发,但不是以确定性的方式。

  #region许可,条款和作者
//
// Schnell - 维基小部件
// Copyright(c)2007 Atif Aziz。版权所有。
//
//作者:
// Atif Aziz,http://www.raboof.com
//
//这个图书馆是免费软件;您可以在
//自由软件基金会发布的GNU宽松公共许可证条款下重新发布和/或修改它
//;版本2.1的许可证,或者(以
//您的选择)任何更新的版本。
//
//这个库分发时希望它有用,但没有
//任何担保;甚至没有隐含的适销性担保或
//特定用途的适用性。有关更多详细信息,请参阅GNU Lesser General Public
//许可证。
//
//您应该收到GNU较宽松通用公共许可证
//以及该库的副本;如果没有,请写信给自由软件基金会
// Inc.,59 Temple Place,Suite 330,Boston,MA 02111-1307 USA
//
#endregion

命名空间WikiPad
{
#region导入

使用System;
使用System.Diagnostics;

#endregion

//
//注意:要使用值为
//类型的SingletonScope和ISingletonScopeHelper,请使用Nullable< T> ;.例如,如果范围
//的值的类型是ThreadPriority,则使用ISingletonScopeHelper< ThreadPriority?>
//和SingletonScope< ThreadPriority?> ;.
//

//
//在调试构建中,此类型被定义为一个类,因此可以使用终结器
//来检测未置备的范围。
//

///< summary>
///旨在改变一个单例和范围的变化。在退出
///作用域后,单例会在输入
///作用域之前恢复到它的值。
///< / summary>

#if!DEBUG
内部结构SingletonScope< T,H>
#else
内部密封类SingletonScope< T,H>
#endif
:IDisposable
其中H:ISingletonScopeHelper< T> ;, new()
{
private T _old;

public SingletonScope(T temp)
{
_old = Helper.Install(temp);
}

private static H Helper
{
get {return new H(); }

$ b $ public void Dispose()
{
//
//首先,将字段传送到堆栈然后将字段加载。
//

var old = _old;
_old = default(T);

//
// Shazam!恢复旧值。
//

Helper.Restore(old);

#if DEBUG
GC.SuppressFinalize(this); //只有当定义为一个类时!
#endif
}

#if DEBUG

//
//此终结器用于检测未定义的范围。这将
//表示范围没有被处置,但是(不幸的是)
//不是哪个和哪个地方,因为GC可能会收集很多晚的
//比应该处理的更多。
//

〜SingletonScope()
{
Debug.Fail(Scope for+ typeof(T).FullName +not dispos!);
}

#endif
}
}






一个完整的工作示例可在 http:// gist.github.com/102424 与编辑说明,但请注意,问题不能确定性地复制到目前为止。 解决方案

您可能会看到的一个奇怪之处在于,即使实例方法仍在运行,终结器仍可以运行,只要该实例方法稍后不使用任何变量即可。因此,在示例代码中, Dispose 方法在第一行之后不使用任何实例变量。即使 Dispose 仍在运行,该实例可以被终止。



如果您将呼叫插入 GC.KeepAlive(this) Dispose 方法的末尾,您可能会发现问题消失。



Chris Brumme有一个博客文章关于这一点,我认为还有另外一个地方......


My observation in practice has been that GC.SuppressFinalize does not always suppress the call to the finalizer. It could be that the finalizer gets called nontheless. I wonder therefore whether GC.SuppressFinalize has the nature of a request rather than a guarantee by the system?


More Information

Following information may help provide more context for the quesiton if needed.

The GC.SuppressFinalize document summary does state that is a request:

Requests that the system not call the finalizer for the specified object.

I wonder if this was a casual use of the word or truly intended to describe the run-time behavior.

I have observed this with the following SingletonScope class taken from the Schnell project, which was based on an original idea by Ian Griffiths except it is more generalized. The idea is to detect, in debug builds, if the Dispose method did get called or not. If not, the finalizer would kick in eventually and one can put up a warning. If Dispose is called then GC.SuppressFinalize should prevent the finalizer from firing. Unfortunately, the warnings seem to fire anyhow, but not in a deterministic fashion. That is, they don't fire on each and every run.

#region License, Terms and Author(s)
//
// Schnell - Wiki widgets
// Copyright (c) 2007 Atif Aziz. All rights reserved.
//
//  Author(s):
//      Atif Aziz, http://www.raboof.com
//
// This library is free software; you can redistribute it and/or modify it 
// under the terms of the GNU Lesser General Public License as published by 
// the Free Software Foundation; either version 2.1 of the License, or (at 
// your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, 
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
//
#endregion

namespace WikiPad
{
    #region Imports

    using System;
    using System.Diagnostics;

    #endregion

    //
    // NOTE: To use SingletonScope and ISingletonScopeHelper with value 
    // types, use Nullable<T>. For example, if the type of value to scope
    // is ThreadPriority then use ISingletonScopeHelper<ThreadPriority?>
    // and SingletonScope<ThreadPriority?>.
    //

    //
    // In debug builds, this type is defined as a class so a finalizer
    // can be used to detect an undisposed scope.
    //

    /// <summary>
    /// Designed to change a singleton and scope that change. After exiting
    /// the scope, the singleton is restored to its value prior to entering
    /// the scope.
    /// </summary>

    #if !DEBUG
    internal struct SingletonScope<T, H> 
    #else
    internal sealed class SingletonScope<T, H> 
    #endif
        : IDisposable 
        where H : ISingletonScopeHelper<T>, new()
    {
        private T _old;

        public SingletonScope(T temp)
        {
            _old = Helper.Install(temp);
        }

        private static H Helper
        {
            get { return new H(); }
        }

        public void Dispose()
        {
            //
            // First, transfer fields to stack then nuke the fields.
            //

            var old = _old;
            _old = default(T);

            //
            // Shazam! Restore the old value.
            //

            Helper.Restore(old);

            #if DEBUG
            GC.SuppressFinalize(this); // Only when defined as a class!
            #endif
        }

        #if DEBUG

        //
        // This finalizer is used to detect an undisposed scope. This will
        // only indicate that the scope was not disposed but (unfortunately)
        // not which one and where since GC will probably collect much later
        // than it should have been disposed.
        //

        ~SingletonScope()
        {
            Debug.Fail("Scope for " + typeof(T).FullName + " not disposed!");
        }

        #endif
    }
}


A full working example is available at http://gist.github.com/102424 with compilation instructions, but do note that the problem cannot be reproduced deterministically so far.

解决方案

One oddity you may be seeing is that the finalizer can still run even while an instance method is still running, so long as that instance method doesn't use any variables later on. So in your sample code, the Dispose method doesn't use any instance variables after the first line. The instance can then be finalized, even though Dispose is still running.

If you insert a call to GC.KeepAlive(this) at the end of the Dispose method, you may find the problem goes away.

Chris Brumme has a blog post about this, and I think there's another around somewhere...

这篇关于GC.SuppressFinalize是否有保证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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