在我的wpf应用程序中,我按以下方式调用新窗口:
_newWin = new WinWorkers_AddWorker();
_newWin.WindowState = this.WindowState;
_newWin.Show();
其中
_newWin
是一个private Window object
。我的问题是,在调用
_newWin
之后,是否应该为_newWin.Show()
分配一个空值?因为垃圾收集器/析构函数会更早地清除空值对象,这会减少内存消耗吗?
谢谢。
最佳答案
将值设置为空通常是不相关的。它很少有用。有时是有害的。
让我们首先考虑最简单的情况:
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
块,则可能发生这种情况)。然后它甚至可以推迟被视为合格对象的时间点。这也许可以忽略不计,但它就在那里。到目前为止很简单;如果我们不去管井,好事情就会发生,而不去管井很容易。
但是,将引用设置为空可能会有好处。考虑:
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,以指示类不再需要使用它,因此我们仍然不会为了将其释放给gc而赋给null。这几乎是可能的,但真的是“不”。
关于c# - 内存消耗代码优化,垃圾收集器理论,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3943093/