C# 垃圾收集如何在对象引用上工作?

C# 垃圾收集如何在对象引用上工作?,c#,.net,asp.net,garbage-collection,static-methods,C#,.net,Asp.net,Garbage Collection,Static Methods,我对对象上的垃圾收集过程感到困惑 object A = new object(); object B = A; B.Dispose(); 通过仅对变量B调用Dispose,创建的对象将不会被垃圾回收 由于该对象仍然由A引用 下面的代码是否与上面的代码相同 public static image Test1() { Bitmap A = new Bitmap(); return A; } 现在我从其他方法调用这个静态函数 public void TestB()

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

object A = new object();
object B = A;        
B.Dispose();
通过仅对变量B调用Dispose,创建的对象将不会被垃圾回收 由于该对象仍然由A引用

下面的代码是否与上面的代码相同

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的作用域完成之前,它会保持活动状态吗

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

Dispose
不会进行垃圾收集。不能显式垃圾收集特定对象。您可以调用
GC.Collect()。调用
Dispose
甚至不会“断开”对象与特定变量的连接,事实上。。。当该变量保持活动状态时(直到JIT最后一次检测到它将再次被读取),它将防止对象被垃圾收集

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


值得注意的是,
Dispose
和垃圾收集是完全不同的事情。调用
Dispose
释放非托管资源(网络连接等)。垃圾收集只是为了释放内存。诚然,垃圾收集可以通过终结,这可能会释放非托管资源作为最后手段,但大多数情况下,您应该明确地处理非托管资源。

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

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

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

好的,首先请处理!=垃圾收集。您可以调用dispose,并且永远不会对其进行垃圾收集,因为“Disposed对象”仍然可以对其进行引用。dispose方法用于在CG运行之前“整理”对象(关闭打开的db连接或文件连接等)

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

public static image Test1()
{
    Bitmap A = new Bitmap();
    return A;
}
这里发生的事情是,您正在创建对象A并返回它,因此当您离开Test1时,A很可能被调用方法中的另一个变量引用。这意味着,即使您已经离开了该方法,A仍然是根(最有可能)的,并且在调用方法完成之前不会被CG

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 
这里正在创建B并调用dispose。这并不意味着它将被收集。一旦程序离开该方法,B就不在范围内,这意味着下次调用GC时可以收集它


这里有很多好的答案,但我还想指出,人们认为您需要IDisposable的原因是GC应该真正命名为MemoryCollector,甚至是ManagedMemoryCollector。GC在收集非托管内存资源(如文件、db连接、事务、windows句柄等)时并不特别聪明

其中一个原因是,托管对象可能有一个非托管资源,它占用了数gig的ram,但对于GC来说,它看起来像8字节左右

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

对于windows句柄,我们需要担心线程相关性。当GC在专用线程中运行时,该线程总是释放windows句柄的错误线程

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

使用()语句是一件好事


注:我经常实现IDisposable,即使我没有任何直接的非托管资源,但重要的是通知所有实现IDisposable的成员变量,这些变量已经调用了Dispose。

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

垃圾收集中的基本问题是,“可以到达这个对象吗?”只要对象上有
public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
}