在我的WPF应用程序中,我按以下方式调用新窗口:
_newWin = new WinWorkers_AddWorker();
_newWin.WindowState = this.WindowState;
_newWin.Show();
_newWin
是private Window object
。
我的问题是,在致电_newWin
后,我应该为_newWin.Show()
分配空值吗?
这会减少内存消耗,因为垃圾收集器/析构函数会更早地清理空值对象吗?
感谢。
答案 0 :(得分:6)
将值设置为null通常无关紧要。它很少有用。它偶尔会有害。
让我们先考虑最简单的情况:
private void DoStuff()
{
var newWin = new WinWorkers_AddWorker();
newWin.WindowState = this.WindowState;
newWin.Show();
int irrelevant = 42;
this.whoCares = irrelevant * 7;
int notRelevantEither = irrelevant + 1;
this.stillDontCare = notRelevantEither * irrelevant;
}
此处newWin
仅存在于此方法中;它是在它中创建的,并且不会通过返回或分配给具有更宽范围的成员而离开方法的范围。
在newWin
收集垃圾时会询问很多人,他们会告诉您它会在this.stillDontCare
行之后发生,因为那时newWin
超出了范围。因此,我们可以在最后一次使用后分配newWin = null
稍微获胜,但它可能微不足道。
从概念上讲,这是正确的,因为我们可以在此之前的任何地方添加处理newWin
的代码,newWin
可供我们使用。
事实上,newWin
很可能在.Show()
之后立即有资格收集。虽然它在概念上处于范围之后,但它实际上并未使用,编译器知道这一点。 (从现在开始,通过“编译器”,我将指的是产生实际运行代码的整个过程,结合IL编译器和抖动)。由于newWin
本身使用的内存(即堆栈上的引用,而不是对象)不再使用,编译器可以将该内存用于irrelevant
或其他内容。没有实时参考,该对象有资格收集。
实际上,如果调用对象的最后几个方法实际上并不使用this
指针(无论是直接使用还是使用成员字段),那么甚至可以在调用这些方法之前收集对象,因为它们是实际上并没有使用该对象。如果你有一个方法,其this
指针从未被使用(再次,直接或间接),那么它可能永远不会被创建!
现在,考虑到这一点,我们可以看到,如果我们在变量超出范围之前为变量赋值null,那么它实际上不会产生甚至可能产生的微小差别。
实际上,分配可能甚至可能需要更长时间才能符合条件,因为如果编译器无法看到变量的使用不会影响对象(不太可能,但也许它如果有try...catch...finally
个区块使得分析更复杂,则可能发生这种情况,然后它甚至可能延迟对象被认为合格的点。这可能是微不足道的,但它就在那里。
到目前为止这么简单;如果我们独自离开,好的事情就会发生,而单独离开也很容易。
然而,引用可以从设置为null中受益。考虑:
public class SomeClass
{
private WorkerThing _newWin;
private void DoStuff()
{
_newWin = new WinWorkers_AddWorker();
_newWin.WindowState = this.WindowState;
_newWin.Show();
}
}
在此考虑,在调用DoStuff()
之后,_newWin
存储在成员变量中。在SomeClass
的实例超出范围之前,它不会超出范围。什么时候会发生?
好吧,我无法回答这个问题,但有时答案很重要。如果SomeClass
本身也是短暂的,那么谁在乎呢。它很快就会超出范围,用它来_newWin
。但是,如果我们分配了_newWin = null
,那么该对象将立即有资格进行收集。
现在,对此有一些重要的警告:
_newWin
没有充分理由成为成员变量。如果上面的示例是完整的代码,我们会将其移回DoStuff()
本地,并且不仅以这种效率方式获得,而且更多,更重要的是我们的正确性,我们不能对来自其他成员的_newWin
做些蠢事。因此,将null赋给成员变量的主要原因仅仅是因为null已成为最合适的值。将null分配给不再使用的成员通常不会尽快释放其内存,但因为它不再适合使用,并且这变得不可能 - 并且明确地向其他代码发出信号 - 当它发生时是空的。
如果引用的持续时间比方法长(因此放入成员变量)和比包含对象和的寿命短得多内存量,然后它可能是分配null将开始有意义。在这种组合发生的非常罕见的情况下,我们可能希望将它指定为null,以表明它不再适用于类,无论如何都要使用,所以我们仍然不会指定null ,目的是将其发布到GC。这几乎是可能的,但真的是“不”。
答案 1 :(得分:2)
垃圾收集不会清除空对象。如果您设置对null
的引用,则只需删除指向对象的引用,以便实际降低其保留计数器。
但是当一个对象超出范围而无法通过代码回收时,这个计数器也会减少。所以你要做的就是没用。
GC会选择仅在不再引用它时才释放它,但是如果你显示那个窗口,你肯定会在某个地方引用它。
编辑:如评论中所述,引用计数可能不是.NET vm的方式(对不起但我不使用M $平台)但原则保持不变。无论如何,您的窗口都不会被GC,因为它是可见的。
答案 2 :(得分:0)
它不会删除对象,因为它将在应用程序的其他地方引用(在内部代码中)否则,将_newWin的值设置为null并将其收集垃圾将使您的窗口消失(并可能导致程序崩溃) ),这不会发生。