清理资源(垃圾收集,使用,IDisposable等)

时间:2011-12-01 17:05:41

标签: c# garbage-collection idisposable

我试图找出如何控制垃圾收集器收集自定义对象的时间 - 我发现很多引用使用IDisposable / Destructors来执行此操作但是每个示例都有如下内容:

class Car
{
    ~Car()  // destructor
    {
        // cleanup statements...
    }
}

(http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx)

“清理声明”中究竟出现了什么?

我希望能够在我的程序关闭时使用该对象的实例调用CarInstance.Dispose()并让GC清理该特定实例 - 这样我在GC时就不会出现性能问题高峰自动运行并清理一堆 -

让我知道! 威廉

6 个答案:

答案 0 :(得分:2)

如果您需要清理.Net无法自动清理的非托管资源,则只应创建终结器。

如果需要清理昂贵的托管或非托管资源,则应实施IDisposable。昂贵并不意味着记忆; “昂贵的”托管资源意味着包装非托管的东西(例如,文件,流,GDI +等)

无法强制GC收集特定对象。

答案 1 :(得分:1)

这取决于你所说的“清理” -

如果你只是提到发布托管内存,那么没有直接的方法来清理对象的内存,只有你的对象。事实上,你不想这样做 - GC非常高效,并试图“控制”它往往会搞砸它的启发式。这是直接调用GC.Collect是个坏主意的部分原因。

如果您正在管理资源,例如本机资源或必须发布的其他类似概念,那么IDisposable是可行的方法。但是,您应该正确实现它,这与您的示例代码非常不同。有关正确实施的详细信息,您可以看到我的series on IDisposable

答案 2 :(得分:1)

除极少数情况外,你不应该试图“控制GC”。几乎可以保证你不会遇到这种情况。如初。

IDisposable.Dispose()并非(直接)与GC或析构函数相关。

  • Dispose()用于清理托管资源,以外的内存。它需要由您的代码显式调用。作为备份,一些类在析构函数中调用它。但是应该在此之前调用它。
  • 析构函数用于清理非托管资源,通常也不是内存。但你也应该在Dispose()中这样做。
  • GC自动运行并完成其工作 - 它可以清理对象使用的内存。你通常不应该试图大惊小怪。

答案 3 :(得分:0)

如果您想控制何时处置特定对象,请为其实施IDisposable并明确调用obj.Dispose()

答案 4 :(得分:0)

要致电CarInstance.Dispose(),必须实施IDisposable然后终结器应调用Dispose(false),以便所有清理代码都在一个位置。

遵循此question中引用的Finalize / Dispose模式。

至于“清理语句”中应包含的内容,这应包含清除任何非托管资源的代码。 .NET无法自行清理的事情。

答案 5 :(得分:0)

以下是我用于存储库的基类代码片段。它利用IDisposable接口来清理Linq-to-SQL上下文。

    /// <summary>
/// Base class for common functionality shared across Sql repositories.
/// </summary>
internal abstract class BaseSqlRepository : IDisposable
{
    #region Members
    /// <summary>
    /// Linq to Sql data context
    /// </summary>
    private SqlRepositoryDataContext context;

    /// <summary>
    /// Determines whether the class has invoked the dispose/finalize functionality.
    /// </summary>
    private bool isDisposed;
    #endregion

    #region Constructors
    /// <summary>
    /// Initializes a new instance of the <see cref="BaseSqlRepository"/> class.
    /// </summary>
    protected BaseSqlRepository()
    {
        this.context = new SqlRepositoryDataContext(InitializeConnectionString());
        this.isDisposed = false;
    }

    protected BaseSqlRepository(SqlRepositoryDataContext Context)
    {
        this.context = Context;
        this.isDisposed = false;
    }

    /// <summary>
    /// Finalizes an instance of the BaseSqlRepository class.
    /// Releases unmanaged resources and performs other cleanup operations before the
    /// <see cref="BaseSqlRepository"/> is reclaimed by garbage collection.
    /// </summary>
    ~BaseSqlRepository()
    {
        this.Dispose(false);
    }

    #endregion

    #region Properties
    /// <summary>
    /// Gets or sets the context.
    /// </summary>
    /// <value>The context.</value>
    protected SqlRepositoryDataContext Context
    {
        get { return this.context; }
        set { this.context = value; }
    }
    #endregion

    #region Methods
    /// <summary>
    /// Initializes the connection string.
    /// </summary>
    /// <returns>Connection string.</returns>
    protected static string InitializeConnectionString()
    {
        string connectionName = ConfigurationManager.AppSettings["AppConnection"];
        string connection = string.Empty;

        if (!string.IsNullOrWhiteSpace(connectionName))
        {
            connection = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
            if (string.IsNullOrWhiteSpace(connection))
            {
                throw new ArgumentException("Unable to initialize a connection to the database.");
            }
        }
        else
        {
            throw new ArgumentException("Unable to initialize a connection to the database.");
        }

        return connection;
    }

    /// <summary>
    /// Releases unmanaged and - optionally - managed resources
    /// </summary>
    /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
    protected void Dispose(bool disposing)
    {
        if (!this.isDisposed && disposing)
        {
            // Dispose the managed resources of the class
            this.context.Dispose();
        }

        // Dipose the un-managed resources of the class
        this.isDisposed = true;
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion
}