垃圾收集,我们应该依赖它吗?

Tom*_*len 6 c# garbage-collection

在代码中,我们说:

using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()))
{
    cn.Open();

    // Set all previous settings to inactive
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn))
    {                            
        cmd.ExecuteNonQuery();
    }

    cn.Close();
}
Run Code Online (Sandbox Code Playgroud)

cn.close在技​​术上是不必要的,因为垃圾收集将为我们处理连接.

但是,我总是喜欢关闭它,不依赖于垃圾收集.这不好吗?浪费时间?或者考虑不依赖自动化的良好做法?

提前感谢您的想法和意见.我将此标记为社区维基,因为它可能是主观的.

Chr*_*ich 15

你永远不应该依赖GC.Raymond Chen 关于此博客文章是一个很好的起点.从本质上讲,如果你没有手动Close/ Dispose您的连接,那么就不能保证它会发生,因为否则只会不会发生时,Dispose从被称为Finalizer这可能不是不会发生:

正确编写的程序不能假定终结器将在程序终止之前的任何时刻运行.

是的,在实践中,您的连接的终结器可能最终会发生,但即使这样,您仍然保持实时连接的时间超过实际需要的时间.如果数据库在任何时候仅允许有限数量的实时连接,则会产生问题.

你正在做的事情被认为是一种好的做法:当你完成资源时,将它们释放出来.如果一个物体是IDisposable,Dispose当你可以的时候.


Vil*_*lx- 6

首先 - 在您的示例中,您使用的是IDisposable界面,它与GC完全无关.从本质上讲,您的代码编译为:

SqlConnection cn = null;
try
{
    cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString());
    cn.Open();

    // Set all previous settings to inactive
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn))
    {
        cmd.ExecuteNonQuery();
    }
    cn.Close();
}
finally
{
    if ( cn != null )
        cn.Dispose();
}
Run Code Online (Sandbox Code Playgroud)

由于cn.Dispose()cn.Close()是相同的在这种情况下-是的,后者是多余的.

现在,如果你想谈论GC,那你就这样写:

    SqlCOnnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString());
    cn.Open();

    // Set all previous settings to inactive
    using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn))
    {
        cmd.ExecuteNonQuery();
    }
    cn = null; // Or just leave scope without doing anything else with cn.
Run Code Online (Sandbox Code Playgroud)

在这种情况下,GC将关闭打开的连接并将其返回池中.在这种情况下,这意味着你无法预测何时发生.在实践中,这段代码(很有可能)会泄漏SqlConnections,很快就会耗尽它们(你会得到一个TimeoutException,因为池中没有可用的连接).

所以,是的,你上面的例子是正确的方法.每当您使用某个实现的对象时IDisposable,将其包装在一个using块中.你不需要打扰.Close(),虽然它也没有伤害.我个人不写它.更少的代码,更少的混乱.