垃圾收集器不会收集使用创建的对象

时间:2011-06-06 16:09:04

标签: c# garbage-collection

我想测试不正确的对象引用并编写一个总是失败的测试。我将测试简化为以下行为:

    [Test]
    public void ScopesAreNotLeaking()
    {
        WeakReference weakRef;
        Stub scope = null;
        using (scope = new Stub())
        {
            weakRef = new WeakReference(scope);
        }
        scope = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Assert.That(weakRef.Target, Is.Null);
    }

然而,这个测试在没有使用的情况下也是如此,通过了:

    [Test]
    public void ScopesAreNotLeaking()
    {
        WeakReference weakRef;
        Stub scope = new Stub();
        weakRef = new WeakReference(scope);
        scope = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Assert.That(weakRef.Target, Is.Null);
    }

使用过的存根类很简单:

class Stub : IDisposable
{
    public void Dispose()  {}
}

有人可以解释一下这种行为,或者 - 甚至更好 - 有一个想法,如何确保对象被垃圾收集?

PS:如果之前有过类似的问题,请耐心等待。我只检查过标题中使用的问题。

4 个答案:

答案 0 :(得分:5)

using不是为了强制垃圾收集而设计的,而是为了确保调用dispose。 Dispose允许您释放非垃圾收集的资源,如文件句柄。当c#很好并准备就绪时就会发生垃圾收集。

答案 1 :(得分:2)

我怀疑使用声明可能会引入本地。在调用GC.Collect之前,使用ildasm查看函数中函数的所有引用是否都已真正清除。还要尝试将using位放在一个返回弱引用的单独函数中。

答案 2 :(得分:1)

标记&扫描GC,就像在.NET中使用的那样,不是确定性的。 即使被GC.Collect()调用,也无法保证真正运行。

此外,using子句与垃圾收集没有任何关系。如果只是在其目标对象上调用Dispose()。

答案 3 :(得分:1)

您的两个测试用例并不完全相同。在using语句结束时,将调用资源的Dispose方法,但不会将其设置为null。调用Dispose不一定会调用析构函数。