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

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

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返回对Bitmap对象的引用。 引用保存在另一个变量B中。通过调用B上的Dispose,B和object之间的连接丢失,但是从Test1传递的引用会发生什么。 它将保持活动状态,直到函数TestB的范围完成?

有没有办法处理从静态函数传递的引用?

我可能会离开,但你似乎对Dispose和垃圾收集有误解。 一旦所有对它的引用都以不确定的方式消失,对象将被垃圾收集。 Dispose通常会摆脱非托管资源,因此对象已准备好进行垃圾回收。 在你的第一个例子中,你处理了对象,理论上使它无法使用,但它仍然存在于堆上,你仍然有一个对它的引用,A和B.一旦这些超出范围,垃圾收集器可能会回收那个内存, 但不总是。 在示例2中,将位图A放置在堆上,然后返回它的引用,并将B设置为该引用。 然后你处理它,B超出范围。 此时不再存在对它的引用,并且稍后将对其进行垃圾收集。

Dispose不垃圾收集。 您无法显式地垃圾收集特定对象。 您可以调用GC.Collect()请求垃圾收集器运行,但这不一样。 调用Dispose甚至不会将对象与特定变量“断开”,实际上……当该变量保持活动状态时(直到JIT最后一次检测到它将再次被读取)它将阻止该对象被垃圾收集。

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

值得注意的是, Dispose和垃圾收集是完全不同的事情。 您调用Dispose来释放非托管资源(网络连接等)。 垃圾收集仅用于释放内存。 不可否认,垃圾收集可以通过最终确定,这可能会释放非托管资源作为最后的手段,但大多数时候您应该明确处理非托管资源。

事实上, Raymond Chen刚刚撰写了一系列博客文章,描述了.NET垃圾收集的各个方面。 这篇文章最直接地与你的问题有关(什么时候垃圾收集对象?)。

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

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

其中一个原因是托管对象可能有一个非托管资源需要几次ram但是对于GC它看起来像8个字节左右。

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

使用Windows句柄我们有线程亲和力来担心。 由于GC在专用线程中运行,因此线程始终是用于释放窗口句柄的错误线程。

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

using()语句是一种祝福。

PS。 我经常实现IDisposable,即使我没有任何直接的非托管资源,但是importnt虽然通知所有实现IDisposable的成员变量,但是已经调用了Dispose。

好的初学者Dispose!= Garbage Collected。 您可以调用dispose并且永远不会收集垃圾,因为“Disposed Object”仍然可以引用它。 dispose方法用于在CG运行之前“清理”对象(关闭打开的数据库连接或文件连接等)。

 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仍然是root(最有可能)并且在调用方法完成之前不会被CG。

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

这里是B正在创建并调用dispose。 这并不意味着它将被收集。 程序离开方法后,B超出范围意味着可以在下次调用GC时收集它。

何时使用Dispose

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

垃圾收集的基本问题是“可以达到这个目标吗?” 只要堆栈上的对象具有对象的引用(或者在对象层次结构中的某处对该对象有引用),该对象就不会被垃圾回收。

例:

ObjA创建一个ObjB,它创建一个ObjC。 Obj C不会被垃圾收集,直到它不再被ObjB引用,或者直到ObjA不再引用ObjB,或者直到没有对象保留对ObjA的引用。

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