问题 C#:在什么情况下你应该删除引用?


CLR Profiler还可以显示哪些方法分配的存储空间超出了您的预期,并且可以发现无意中保留对无用的对象图的引用的情况,否则这些对象图可能被GC回收。 (一个常见的问题设计模式是一个软件缓存或项目的查找表,这些项目不再需要或以后可以安全地重建。当缓存使对象图表保持活动超过其使用寿命时,这是悲剧性的。 一定要将对不再需要的对象的引用置空。) - 编写更快的托管代码

我认为我之前没有真正搞过一个参考。我假设你并不总是需要这样做,但我想也有时候记得这么做很重要。但是,那是什么情况呢?什么时候应该删除引用?


8697
2017-10-19 06:38


起源



答案:


只有当持有引用的变量保持“活动”但你不希望引用本身阻止垃圾收集时,你才需要这样做。换句话说,如果对象A持有对象B的引用,并且您不再需要B,但A将因其他原因而保持活动状态。另一个常见的例子是静态变量,只要AppDomain是“活着的”。

对于局部变量,它是 几乎 从不需要,因为GC可以检测代码中最后一个可能访问变量的点。但是,如果在第一次迭代期间使用在循环外声明的变量,但是您知道在后续迭代中不需要它,那么 可以 将其设置为null以帮助该对象更早地符合GC的条件。

根据我的经验,这是 非常 在这种情况下很难找到自己。为了GC,我几乎没有考虑将变量设置为null。通常,对象中的所有成员变量都是“有用的”,直到对象本身符合GC的条件。如果你发现自己有成员变量  对于对象的整个生命周期有用,您可能希望查看是否表示设计存在问题。


11
2017-10-19 06:45



说得通。想想我也是这样做的,只是没有真正考虑它。 - Svish


答案:


只有当持有引用的变量保持“活动”但你不希望引用本身阻止垃圾收集时,你才需要这样做。换句话说,如果对象A持有对象B的引用,并且您不再需要B,但A将因其他原因而保持活动状态。另一个常见的例子是静态变量,只要AppDomain是“活着的”。

对于局部变量,它是 几乎 从不需要,因为GC可以检测代码中最后一个可能访问变量的点。但是,如果在第一次迭代期间使用在循环外声明的变量,但是您知道在后续迭代中不需要它,那么 可以 将其设置为null以帮助该对象更早地符合GC的条件。

根据我的经验,这是 非常 在这种情况下很难找到自己。为了GC,我几乎没有考虑将变量设置为null。通常,对象中的所有成员变量都是“有用的”,直到对象本身符合GC的条件。如果你发现自己有成员变量  对于对象的整个生命周期有用,您可能希望查看是否表示设计存在问题。


11
2017-10-19 06:45



说得通。想想我也是这样做的,只是没有真正考虑它。 - Svish


重要的是,如果你有长期存在的对象(比如你的引用中的缓存示例),它们持有对短期对象(如缓存项)的引用。长生活对象的其他示例可以是单例对象,Windows窗体应用程序中的主窗体实例,ASP.NET应用程序的应用程序实例等。

我想添加另一个常见的pitfull:订阅由长期存在的对象发布的事件的短期对象。由于事件发布者拥有对所有订阅者的引用,因此如果您不取消订阅,则不会收集订阅者(例如,仅需要几毫秒的ASP.NET页面或控件实例)。


4
2017-10-19 06:48



一个特别令人震惊的例子是Windows窗体中的主题控件(例如 ToolStrip),当它们变为可见时注册Windows主题更改事件,如果在取消引用它们之前未将Visible设置为false,则不注销它们自己。如果你的应用程序创建并销毁了很多这些对象,你可能会遇到麻烦 - 特别是如果你期望这些控件持有引用的对象也会被垃圾收集。每当主题出现时我就会把它拿出来,因为它是一种深刻的创伤。 - Robert Rossney


当你知道它们不会被垃圾收集时,你应该删除你不再需要的对象的引用。

如果你有 有效的Java 如图5所示,有一个堆栈实现的例子,它有内存泄漏,因为对象引用没有被删除。如果您没有该书,可以在Google图书上查看该部分 这里


1
2017-10-19 06:49



那本书中的好例子:) - Svish