内存消耗代码优化,垃圾收集器理论 [英] Memory consuption code optimization, a garbage collector theory

查看:91
本文介绍了内存消耗代码优化,垃圾收集器理论的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my WPF-application, I call new windows in the following way:

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

_newWinprivate Window object的地方.

我的问题是,在调用_newWin.Show()之后是否应该为_newWin分配一个空值?

My question is should I assign a null value to _newWin after I call _newWin.Show()?

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

Will this decrease memory consumption because garbage collector / destructor will clean the null value objects earlier?

谢谢.

推荐答案

将值设置为null通常无关紧要.它很少有用.有时是有害的.

It's generally irrelevant to set a value to null. It's very rarely useful. It's occasionally harmful.

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

Let's consider first the simplest case:

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

Here newWin only exists in this method; it is created in it and doesn't leave the scope of the method by being returned or assigned to a member with a wider scope.

newWin被收集到垃圾时,会问很多人,他们会告诉您这将在this.stillDontCare行之后发生,因为那是newWin超出范围的时候.因此,通过在newWin = null上次使用后分配它,可以略胜一筹,但是它可能可以忽略不计.

Ask a lot of people when newWin gets garbage collected, and they'll tell you that it will happen after the line with this.stillDontCare, because that's when newWin goes out of scope. We could therefore have a slight win by assigning newWin = null just after its last use, but its probably negligible.

从概念上讲,这是正确的,因为我们可以添加处理newWin的代码,直到那时为止,而newWin可供我们使用.

Conceptually this is true, because we can add code that deals with newWin anywhere up until that point, and newWin is there for us to make use of.

实际上,newWin很可能在.Show()之后立即有资格进行收集.尽管从概念上讲它在此之后才是范围,但实际上并没有使用它,并且编译器也知道这一点. (从现在开始,通过编译器",我指的是将IL编译器和抖动结合在一起的,产生实际运行代码的整个过程).由于不再使用newWin本身使用的内存(即堆栈上的引用,而不是对象),因此编译器可以将该内存用于irrelevant或其他用途.没有实时引用,该对象可以收集.

In fact though, it is quite likely that newWin becomes eligible for collection right after .Show(). While it is conceptually in scope after then, it isn't actually used and the compiler knows that. (By "compiler" from now on I'm going to mean the entire process that produces actual running code, combining the IL compiler and the jitter). Since the memory used by newWin itself (that is, the reference on the stack, not the object) is no longer used the compiler could use that memory for irrelevant or something else. There being no live reference any more, the object is eligible for collection.

的确,如果在对象上调用的最后几种方法实际上并没有使用this指针(无论是直接使用还是通过使用成员字段),则甚至可以在调用这些方法之前收集该对象,因为它们不会实际使用该对象.如果您有一个从未使用过(c15)指针的方法(再次,直接或间接地),那么它可能永远不会被创建!

Indeed, if the last few methods called on an object don't actually use the this pointer (whether directly or by using member fields) then the object can even be collected before those methods are called, because they don't actually make use of the object. If you had a method whose this pointer was never used (again, directly or indirectly) then it might never actually be created!

现在,记住这一点,我们可以看到,如果我们在变量超出范围之前为变量赋null的话,它实际上并不会产生看起来可能会产生的细微差别.

Now, bearing this in mind, we can see that it really isn't going to make even that slight negligible difference that it would seem to make, if we were to assign null to the variable before the variable falls out of scope.

实际上,赋值甚至可能需要更长的时间才能符合条件,因为如果编译器看不到变量的使用不会影响对象(不太可能,但是也许如果存在try...catch...finally块可能会使分析变得更加复杂),那么它甚至可能会延迟该对象被视为合格的时间.它可能再次可以忽略不计,但是它在那里.

Indeed, it is just about possible that the assignment could even make it take longer to become eligible, because if the compiler couldn't see that that use of the variable was not going to affect the object (unlikely, but perhaps it could happen if there are try...catch...finally blocks making the analysis more complicated), then it could even delay the point at which the object is deemed eligible. It is again probably negligible, but it is there.

到目前为止非常简单;如果我们独自一人离开,好事就会发生,而独自一人离开很容易.

So far so simple; good stuff happens if we leave well alone, and leaving well alone is easy.

但是,将引用设置为null可能会使引用受益.考虑:

It is however possible for a reference to benefit from being set to null. Consider:

public class SomeClass
{
  private WorkerThing _newWin;
  private void DoStuff()
  {
    _newWin = new WinWorkers_AddWorker();
    _newWin.WindowState = this.WindowState;
    _newWin.Show();
  }
}

在此考虑,这次调用DoStuff()之后,_newWin存储在成员变量中.在SomeClass的实例超出范围之前,它不会超出范围.什么时候会发生?

Consider here, that this time after DoStuff() is called, _newWin is stored in a member variable. It will not fall out of scope until the instance of SomeClass falls out of scope. When will that happen?

嗯,我不能回答这个问题,但是有时候答案很重要.如果SomeClass本身也是短暂的,那么谁在乎.它很快就会超出范围,并带有_newWin.但是,如果我们分配了_newWin = null,则该对象将立即有资格进行收集.

Well, I can't answer that question, but sometimes the answer is important. If the SomeClass itself is also short-lived, then who cares. It'll fall out of scope soon enough, taking _newWin with it. If however, we assigned _newWin = null then the object would immediately be eligible for collection.

现在,对此有一些重要警告:

Now, some important caveats to this:

  1. 首先,没有充分的理由将_newWin用作成员变量.如果上面的示例是完整的代码,我们将把它移回DoStuff()本地,不仅以这种有效方式获得收益,而且,在我们获得正确机会的过程中,更重要的是,我们可以不会对另一个成员的_newWin做愚蠢的事情.
  2. 如果我们坚持使用成员变量中的某些内容,则可能是有充分理由的.这样做有一个很好的理由,那就是不要为尽可能快地清除变量而狂热.
  3. 大多数对象无论如何都不会占用太多内存.一个成员变量在这里或那里都不会受到伤害.
  1. In the first place, there is no good reason for _newWin to be a member variable. If the example above were complete code we would move it back to being local to DoStuff() and gain not only in this efficiency manner, but much, much more importantly in our chances of correctness, as we can't do something stupid to _newWin from another member.
  2. If we are holding onto something in a member variable, it's probably for a good reason. That good reason is going to override being fanatic about cleaning out variables as fast as possible.
  3. Most objects just don't take up that much memory by themselves anyway. A member variable here or there isn't going to hurt.

因此,将null分配给成员变量的主要原因仅是因为null已成为最合适的值.为不再使用的成员分配null通常不会尽快释放其内存,但是因为它不再适合使用,并且变得不可能-并明确地向其他代码发出信号-当它不再使用时为空.

Because of this, the main reason to assign null to a member variable, is simply because null has become the most appropriate value. Assigning null to a member that is no longer going to be used is generally not to release its memory ASAP but because it is no longer appropriate to use, and that becomes impossible - and clearly signalled to the rest of your code as such - when it is null.

如果引用的寿命比方法的寿命长(并因此放入成员变量中),则 的寿命比包含对象的寿命短,并且消耗的时间非常长大量的内存,那么很有可能分配null将变得有意义.在发生这种组合的极少数情况下,我们可能希望将其分配为null,以表示该类不再可以使用,因此我们仍然不会出于以下目的分配null 将其释放到GC.这几乎是可能的,但实际上是"nah".

If a reference was longer-lived than a method (and hence put in a member variable) and considerably shorter-lived than the containing object and consumed a very large amount of memory, then it's just about possible that assigning null would begin to make sense. In the extremely rare cases where that combination happens, we probably want to assign it to null to indicate that it is no longer there for the class to use anyway, so we're still not going to assign null with the purpose of releasing it to the GC. It's just about possible, but really "nah".

这篇关于内存消耗代码优化,垃圾收集器理论的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆