物体复活的用法

我的.NET Windows服务应用程序中存在内存泄漏问题。 所以我开始阅读有关.NET内存管理的文章。 我在Jeffrey Richter的一篇文章中找到了一个有趣的练习。 这个练习名称是“对象复活”。 它看起来像是将全局或静态变量初始化为“this”的位置代码:

protected override void Finalize() { Application.ObjHolder = this; GC.ReRegisterForFinalize(this); } 

我知道这是一个不好的做法,但我想知道使用这种做法的模式。 如果你知道,请写在这里。

推测:在Pool情况下,如ConnectionPool。

您可以使用它来回收未正确处理但应用程序代码不再包含引用的对象。 您不能将它们保存在池中的列表中,因为这会阻止GC收集。

来自同一篇文章:“复活的好用途很少,如果可能,你真的应该避免它。”

我能想到的最佳用途是“回收”模式。 考虑一个生产昂贵的,几乎不可改变的物体的工厂; 例如,通过解析数据文件,或通过反映程序集或深度复制“主”对象图来实例化对象。 每次执行这个昂贵的过程时,结果都不太可能改变。 从头开始避免实例化符合您的最佳利益; 但是,由于某些设计原因,系统必须能够创建许多实例(没有单例),并且您的消费者无法了解工厂,以便他们可以“返回”对象本身; 他们可能会注入对象,或者获得一个工厂方法委托,从中获取引用。 当依赖类超出范围时,通常也是实例。

一个可能的答案是覆盖Finalize(),清理实例的任何可变状态部分,然后只要Factory在范围内,就将实例重新附加到Factory的某个成员。 这允许垃圾收集过程实际上“回收”这些对象的有价值部分,否则它们将超出范围并被完全破坏。 工厂可以查看它的“垃圾箱”中是否有可用的回收物品,如果有,它可以将其抛光并将其移出。 如果进程使用的总对象数增加,则工厂只需要实例化对象的新副本。

其他可能的用途可能包括一些高度专业化的记录器或审计实现,您希望在其死后处理的对象将自己附加到由此过程管理的工作队列。 在该过程处理它们之后,它们可以完全被破坏。

一般来说,如果你想要家属思考他们是摆脱一个对象,或者不必打扰,但你想保留实例,复活可能是一个很好的工具,但你必须仔细观察它避免接收复活的引用的对象变成“打包老鼠”的情况,并保留在进程的生命周期内在内存中创建的每个实例。

我的一个兄弟曾经在高性能仿真平台上工作过一次。 他告诉我如何在应用程序中,对象构造是应用程序性能的一个明显瓶颈。 看起来对象很大并且需要一些重要的处理来初始化。

他们实现了一个对象存储库来包含“已退役”的对象实例。 在构造新对象之前,他们首先检查存储库中是否已存在。

权衡是增加内存消耗(因为一次可能存在许多未使用的对象)以提高性能(随着对象构造的总数减少)。

请注意,实现此模式的决定是基于他们在特定方案中通过分析观察到的瓶颈。 我希望这是一个特例。

我可以想到使用它的唯一地方可能是当你试图清理资源时,资源清理失败了。 如果重新尝试清理过程至关重要,那么从技术上讲,您可以“重新注册”要完成的对象,这有望成功,第二次。

话虽如此,我在实践中完全避免这种情况。

据我所知,.net没有特定的顺序调用终结器。 如果你的类包含对其他对象的引用,那么在调用终结器时它们可能已经完成(因此也就是Disposed)。 如果您决定复活对象,则会引用最终/处置对象。

 class A { static Set resurectedA = new Set(); B b = new B(); ~A() { //will not die. keep a reference in resurectedA. resurectedA.Add(this); GC.ReRegisterForFinalize(this); //at this point you may have a problem. By resurrecting this you are resurrecting b and b's Finalize may have already been called. } } class B : IDisposable { //regular IDisposable/Destructor pattern http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx }