.NET:有没有办法知道对象何时被释放/垃圾回收?

7
给定一个对象,有没有任何方法可以在该对象被垃圾收集时得到通知?
我正在尝试让C#扩展方法更像混入(特别是添加日志记录)。因此,每个对象都会获得一个新的Logger()方法,该方法返回一个ILog,该ILog根据扩展方法的目标对象创建并缓存。
效果很好,唯一的问题显然是当一个对象消失后,它的日志记录器可能会挂起相当长的时间。当然,我可以设置一些定期机制来扫描日志记录器缓存并清除它,但我更愿意设置一些垃圾收集通知,以便了解系统何时不再使用我的对象。
有人知道如何做到这一点吗?
3个回答

11

我认为通常做法是维护一个WeakReferences列表。使用弱引用,可以通过检查 IsAlive 属性来确定您所引用的对象是否已被垃圾回收。


3
在 .net 4.0 中,有一种类型叫做 ConditionalWeakTable ,可以用来请求通知任意对象何时变为可终结对象,虽然使用起来可能有些笨拙。如果一个 ConditionalWeakTable 包含了将一个对象(比如说第451个被创建的对象)映射到另一个对象(比如说第730个被创建的对象)的条目,则只要该条目仍然存在于表中,并且对表和对象#451都存在根引用,表就会被视为指向对象 #730 的根引用。如果没有指向对象 #451 的根引用,则该表将不再是指向对象 #730 的根引用。
因此,如果对象 #730 持有对表和对象 #730 在表外的引用,则对象 #730 将在与对象 #451 相同的时间变为可终结对象。如果对象 #730 覆盖了Finalize(),那么该覆盖可以用作通知对象 #451 变为可终结对象的方法。
请注意,即使对象 #451 复活并重新注册了终结操作,对象 #730 的终结器也只会触发一次。尽管有可能编写代码,在对象 #451 确实死亡和消失之前,即使它复活几次,也可以在其周围发出通知,但这没有特别简洁的方法。

拥有一个管理此类并抽象出丑陋部分的类,为调用客户端提供漂亮界面,这将非常棒。另外,从我所读的内容来看,似乎一个对象只能被复活一次?这准确吗?来源:http://www.philosophicalgeek.com/2014/08/20/short-vs-long-weak-references-and-object-resurrection/ - Mike-E

1

1
很有趣。我总是听到它们被称为“Finalizers”。术语改变了吗,还是我一直错了? - Dave Markle
1
我认为这取决于编程语言。在C#中,“析构函数”似乎是指实现“终结器”的语言结构。然而,在C++/CLI中,称为“析构函数”的语言结构(例如~class() {...})实际上实现了“IDispose”接口,同时还有一个新的语言结构称为“终结器”(例如!class() {...}),它与C#中的“析构函数”相同。 - stakx - no longer contributing
是的,但这意味着我必须创建一个析构函数,调用类似于 this.ReleaseLogger() 的东西。这不是一个坏主意,但我更愿意避免这样做。 - George Mauer
@Darin:实际上,在GC检测到对象不可达之后,析构函数才会被调用,但在对象内存实际回收之前(只有当对象仍然不可达时,内存才会被回收,因为析构函数有使死亡对象复活的能力)。 - Thomas Pornin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接