代码之家  ›  专栏  ›  技术社区  ›  Mike Omeiri Kouider

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

  •  4
  • Mike Omeiri Kouider  · 技术社区  · 14 年前

    在我的WPF应用程序中,我按以下方式调用新窗口:

    _newWin = new WinWorkers_AddWorker();
    _newWin.WindowState = this.WindowState;
    _newWin.Show();
    

    在哪里? _newWin private Window object .

    我的问题是我应该给 我打电话之后 _newWin.Show()

    因为垃圾收集器/析构函数会更早地清除空值对象,这会减少内存消耗吗?

    谢谢。

    3 回复  |  直到 10 年前
        1
  •  6
  •   Jon Hanna    14 年前

    将值设置为空通常是不相关的。它很少有用。有时是有害的。

    让我们首先考虑最简单的情况:

    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 仅存在于此方法中;它是在其中创建的,并且不会通过返回或分配给具有更大范围的成员而离开方法的范围。

    问很多人什么时候 纽温 收集垃圾,他们会告诉你 this.stillDontCare ,因为那时 超出范围。因此,我们可以通过分配 newWin = null 就在它最后一次使用之后,但它可能可以忽略不计。

    在概念上这是正确的,因为我们可以添加处理 纽温 在那之前的任何地方 纽温 我们可以利用它吗。

    事实上,很可能 纽温 .Show() . 虽然它在之后的概念范围内,但实际上并没有使用它,编译器知道这一点。(从现在开始,我所说的“编译器”是指产生实际运行代码的整个过程,包括IL编译器和抖动)。因为 纽温 irrelevant 或者别的什么。如果不再有活动引用,则该对象符合收集条件。

    实际上,如果对对象调用的最后几个方法实际上没有使用 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 超出范围。什么时候会发生?

    某个阶级 本身也是短命的,那谁在乎呢。很快就会超出范围 _纽温 带着它。但是,如果我们 _newWin = null

    现在,有一些重要的注意事项:

    1. 首先,没有充分的理由 _纽温 多斯塔夫() 不仅如此,而且 因为我们不能做蠢事 _纽温 来自另一个成员。
    2. 如果我们在一个成员变量中持有某种东西,这可能是有充分理由的。这个很好的理由将取代对尽快清除变量的狂热。
    3. 不管怎样,大多数对象本身并不占用那么多内存。这里有一个成员变量,否则就不会有伤害。

    因此,将null赋给成员变量的主要原因,仅仅是因为null已经成为最合适的值。将空值分配给不再使用的成员通常不是为了尽快释放其内存,而是因为它不再适合使用,并且当它为空值时,这将变得不可能——并且清楚地指示给其他代码。

    如果引用的生存期比方法长(因此放入成员变量) 消耗了大量的内存,那么分配空就有可能开始有意义了。在这种组合出现的极少数情况下,我们可能希望将其赋给null,以指示类不再需要使用它,因此我们仍然不打算赋给null 目的是

        2
  •  2
  •   Jack    14 年前

    垃圾收集不清除空对象。如果您将引用设置为 null 只需移除指向对象的引用,以便实际降低其保留计数器。

    GC仍然会选择仅在不再引用它时才释放它,但是如果您显示该窗口,您将确保它仍然被引用到某个地方。。

    编辑 :如注释中所述,引用计数可能与.NET虚拟机不同(抱歉,我不使用M$platform),但原理不变。因为你的窗口是可见的,所以无论如何也不会被GCed。

        3
  •  0
  •   Kendrick    14 年前