当对象被垃圾收集时,是否释放了非处置资源?

时间:2014-02-19 12:38:56

标签: c# garbage-collection

我提出了这个问题,虽然我相信我知道答案,但我相信我应该100%肯定我开始散布错误的信息!

我有这个对象:

public class MyObj(){
    private SqlConnection conn;

    public MyObj(string connString){
        var stream = File.Open(@"c:\\file.txt");
        conn = new SqlConnection(connString);
    }
}

创建此对象时,文件句柄与文件关联,并创建与数据库的连接。 Dispose没有按原样调用它。

当这个对象超出范围并最终被垃圾收集时,这两个资源会被释放,还是会留在内存中?

3 个答案:

答案 0 :(得分:2)

  

当这个对象超出范围并最终被垃圾收集时,这两个资源会被释放,还是会留在内存中?

通常某些类型 - 通常在某种程度上隐藏在公共API中 - 在本机资源上有一个句柄,可能是通过SafeHandle,这就是最终释放资源的内容。当然,可能编写不执行此操作的代码,在这种情况下,本机资源只能通过正常的OS清理在进程退出时释放,但我希望任何Microsoft - 提供API以做正确的事情。

当然,您仍应明确处置资源:)

答案 1 :(得分:1)

任何直接使用非托管资源(如文件句柄或数据库连接)的对象都应始终实现释放非托管资源的finalizer。当对象被垃圾收集时,执行终结器并释放非托管资源。所以回答你的问题:

  

当这个对象超出范围并最终被垃圾收集时,这两个资源会被释放,还是会留在内存中?

,非托管资源最终会被调用该对象的终结器的垃圾收集器释放。

如您所知,将其留给垃圾收集器来清理非托管资源通常是件坏事。如果您打开并读取文件,那么当垃圾收集器决定释放现在未使用的文件对象时,您希望该文件在读取完成后关闭并可供其他进程使用。

.NET提供IDisposable接口以启用非托管资源的确定性释放。当您处置FileStream对象时,将释放基础非托管文件句柄并关闭该文件。

实现IDisposable接口的一个重要部分是,如果通过调用Dispose释放非托管资源,则不再需要最终确定该对象。这就是为什么当对象实现IDisposable并具有终结器时,您会看到对GC.SuppressFinalize(this)的调用。避免最终化是减少垃圾收集器必须使用的资源量的好事。此外,终结器在垃圾收集器建立的严格限制范围内运行,因此最好避免使用它们。

请注意,大多数情况下,您的对象没有终结器,因为您不使用任何非托管资源。相反,您将使用SafeHandle等托管对象访问非托管资源。在这种情况下,对象不需要终结器,但应实现IDisposable并将对Dispose的调用转发给任何聚合的IDisposable对象。

答案 2 :(得分:0)

简短回答:它们是自动释放的。

多年前的一次,由于物体没有被释放,我得到了一个莫名其妙的内存泄漏。 当时我需要对垃圾收集器进行一些显式调用来解决问题。

从未找到真正的原因,可能是框架错误,可能与操作系统资源有关,但我可以说99.99%的时间可以免除C#中的担忧。