代码之家  ›  专栏  ›  技术社区  ›  kishore

垃圾收集如何处理对象引用?

  •  9
  • kishore  · 技术社区  · 15 年前

    我对对象上的垃圾收集过程感到困惑。

    object A = new object();
    object B = A;        
    B.Dispose();
    

    通过只对变量B调用Dispose,创建的对象将不会被垃圾收集。 因为对象仍被引用。

    下面的代码和上面的代码一样吗?

    public static image Test1()
    {
        Bitmap A = new Bitmap();
        return A;
    }
    

    现在我从其他方法调用这个静态函数。

    public void TestB()
    {
       Bitmap B = Test1();
       B.Dispose();
    } 
    

    静态函数test1返回了对位图对象的引用。引用已保存 在另一个变量b中。通过在b上调用Dispose,b和对象之间的连接将丢失,但从test1传递的引用将发生什么情况。在函数testb的作用域完成之前,它是否保持活动状态?

    是否有任何方法可以立即处理从静态函数传递的引用?

    7 回复  |  直到 15 年前
        1
  •  15
  •   Yuriy Faktorovich    15 年前

    我可能走了,但你好像对 Dispose 以及垃圾收集。一旦对象的所有引用都消失了,将以非确定性的方式对其进行垃圾收集。Dispose通常会除去非托管资源,因此对象已准备好进行垃圾收集。在第一个示例中,您释放了对象,理论上使其不可用,但它仍然存在于堆中,并且您仍然具有对它的引用(A和B)。一旦这些超出范围,垃圾收集器可能会回收该内存,但并不总是如此。在示例2中,将位图A放置在堆上,然后返回对它的引用,并将B设置为该引用。然后你处理它,B就超出了范围。此时不再存在对它的引用,稍后将对其进行垃圾收集。

        2
  •  16
  •   Jon Skeet    15 年前

    Dispose 垃圾收集。不能显式地垃圾收集特定对象。你可以打电话 GC.Collect() 哪一个 请求 垃圾收集器运行,但情况不同。打电话 处置 实际上,它甚至不会“断开”对象与特定变量的连接…当该变量保持活动状态(直到最后一次JIT检测到它将再次被读取)时,它将阻止对象被垃圾收集。

    在对象不再被任何对象引用之前,它不会被垃圾收集。诚然,在某些极端情况下,这可能比你想象的要早,但你很少需要担心这些。

    值得注意的是 处置 垃圾收集是非常不同的事情。你打电话 处置 释放 非受管的 资源(网络连接等)。垃圾收集只是为了释放内存。诚然,垃圾收集可以进行终结,这可能会作为最后的手段释放非托管资源,但大多数时候您应该显式地处理非托管资源。

        3
  •  5
  •   Daniel Pratt    15 年前

    碰巧 Raymond Chen 刚刚写了一系列描述.NET垃圾收集方面的博客文章。 This post 最直接的关系到您的问题(对象何时被垃圾收集?).

        4
  •  3
  •   siride    15 年前

    Dispose()与垃圾收集没有任何关系。它所做的只是允许确定性的资源释放,但是您必须显式地调用它。当调用Dispose()时,调用它的对象不会被垃圾收集。当所有对它的引用都消失时,它将有资格进行垃圾收集。

        5
  •  2
  •   Just another metaprogrammer    15 年前

    这里有许多很好的答案,但我也想指出,人们认为您需要IDisposable的原因是,一个GC实际上应该命名为memorycollector,甚至是managedmemorycollector。GC在收集非托管内存资源(如文件、db conn、事务、Windows句柄等)时并不特别聪明。

    其中一个原因是,一个托管对象可能拥有一个非托管资源,该资源需要几Gigs的RAM,但是对于GC来说,它看起来像8个字节左右。

    对于文件、db conn等,您通常希望尽快关闭它们,以释放非托管资源并避免锁定问题。

    对于Windows句柄,我们有线程关联性需要考虑。当GC在专用线程中运行时,该线程始终是释放Windows句柄的错误线程。

    因此,GC有助于避免泄漏托管内存和减少代码混乱,但仍应尽快释放非托管资源。

    使用()语句是一种祝福。

    ps.我经常实现IDisposable,即使我没有任何直接的非托管资源,但它的重要作用并不是通知实现IDisposable的所有成员变量,这些变量被调用了Dispose。

        6
  •  1
  •   kemiller2002    15 年前

    好的,先处理!=垃圾收集。您可以调用Dispose,而从不将其垃圾收集,因为“Disposed对象”仍然可以有对它的引用。Dispose方法用于在CG运行之前“整理”对象(关闭打开的DB连接或文件连接等)。

    object A = new object();
    object B = A;        
    B.Dispose();
    

    在此实例中,B.Dispose正在对A调用Dispose方法,因为B正在引用变量A中的对象。这两者都不是CGD,因为它们尚未超出范围。

    public static image Test1()
    {
        Bitmap A = new Bitmap();
        return A;
    }
    

    这里所发生的是,您正在创建对象A并返回它,所以当您离开test1时,A很可能被调用方法中的另一个变量引用。这意味着即使您已经离开了方法,a仍然是根的(很可能),并且在调用方法完成之前不会被cg'd。

    public void TestB()
    {
       Bitmap B = Test1();
       B.Dispose();
    } 
    

    这里正在创建B并调用Dispose。这并不意味着它会被收集起来。一旦程序离开方法,b就超出了范围,这意味着下次调用GC时可以收集它。

    When to use Dispose

        7
  •  0
  •   Jason    15 年前

    值得注意的是,调用Dispose实际上可能什么也不做。它使对象有机会清理数据库连接和非托管资源等资源。如果有包含非托管资源(如数据库连接)的对象,则Dispose将告诉该对象是时候清除这些引用。

    垃圾收集中的基本问题是,“可以到达这个对象吗?”只要栈中的对象上有对您的对象的引用(或者在对象层次结构中的某个地方有对该对象的引用),就不会对该对象进行垃圾收集。

    例子:

    obja创建一个objb,它创建一个objc。在objb不再引用objb之前,或者在objb不再被obj a引用之前,或者在没有对象保留对obj a的引用之前,不会对obj c进行垃圾收集。

    同样,要问的问题是,“这个对象当前是否可以被代码中的任何内容引用?”

    推荐文章