c# - 内存消耗代码优化,垃圾收集器理论

标签 c# wpf optimization memory destructor

在我的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/

相关文章:

c# - 如何将其转换为使用 Linq 到数据集?

c# - WPF 运行时区域设置更改,重新评估 ValueConverters UI

wpf - 如果RelativeSource不存在则隐藏DataTrigger

c# - WPF层事件分离

algorithm - 在战列舰游戏中确定船只是否被击中的最有效方法是什么?

c# - 拒绝字符串变量中的字符串

c# - 通过 C# 和 SMO 检查和删除现有表

c# - 使用 C# 读取 doc 和 docx 文件,而无需在服务器上安装 MS Office

algorithm - 构建具有最大值的表达式

python - Python 中的非顺序循环优化