可变寿命 [英] Variable lifetime

查看:66
本文介绍了可变寿命的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当执行行超出代码块之外时,变量发生了什么? 例如:

What happends to variable when line of execution goes outside of code block? For example:

1  public void myMethod()
2  {
3     int number;
4     number = 5;
5  }

所以,我们声明并设置变量.当它超出代码块(第5行)时,变量号发生了什么?

so, we declare and set variable. When it goes outside of code block (line 5) what happends to variable number?

这是创建类实例的另一个示例:

Here is another example with creating instance of class:

7   public void myMethod()
8   {
9      Customer myClient;
10     myClient = new Customer();
11  }

当它超出代码块(第11行)时,对象引用myClient会发生什么?

When it goes outside of code block (line 11) what happends to object reference myClient?

我猜这两种情况都分配了变量,但是当它被释放时呢?

I guess in both cases variable is allocated but when it is deallocated?

推荐答案

作为变量,它是C#语言中的一个概念.在代码块外部没有任何意外发生",因为它在代码块内部.这句话外面的 word 一词什么都没有发生.

As a variable it's a concept in the C# language. Nothing "happens" to it outside of the code block, because it is inside the code block. Nothing happens to the word word outside this sentence.

当然,您的意思是在代码运行时变量变成了什么东西,但是值得记住这一区别,因为在考虑这个问题时,我们转移到了变量在C#中不如在变量中的水平.

Of course, you mean what happens to the thing that variable becomes when the code is run, but it's worth remembering the distinction, because in considering that question we're shifting to levels where variables are not as they are in C#.

在两种情况下,代码都会转换为CIL,然后在运行时转换为机器代码.

In both cases the code is turned into CIL, and then into machine code when it is run.

CIL可能相差很大.例如,以下是在调试模式下编译时第一个的外观:

The CIL could differ quite a bit. For example, here's how the first looks when compiled in debug mode:

.method public hidebysig instance void myMethod () cil managed 
{
  .locals init ([0] int32) // Set-up space for a 32-bit value to be stored
  nop                      // Do nothing
  ldc.i4.5                 // Push the number 5 onto the stack
  stloc.0                  // Store the number 5 in the first slot of locals
  ret                      // Return
}

这是编译发布时的外观:

And here's how it looks when compiled to release:

.method public hidebysig instance void myMethod () cil managed 
{
  ret                      // Return
}

由于未使用该值,因此编译器将其删除为无用的残差,而只是编译立即返回的方法.

Since the value isn't used, the compiler removes that as useless cruft and just compiles a method that immediately returns.

如果编译器未删除此类代码,则我们可能会期望以下内容:

If the compiler didn't remove such code, we might expect something like:

.method public hidebysig instance void myMethod () cil managed 
{
  ldc.i4.5                 // Push the number 5 onto the stack
  pop                      // Remove value from stack
  ret                      // Return
}

调试版本将存储的内容存储的时间更长,因为检查它们对于调试很有用.

Debug builds store things for longer, because examining them is useful for debugging.

当发布版本确实将内容存储在本地数组中时,它们也更有可能在方法中重用插槽.

When release builds do store things in the array of locals, they are also more likely to reuse slots within the method.

然后将其转换为机器代码.这将类似于它的工作方式,将产生数字5,将其存储在本地(在堆栈上或在寄存器中),然后再次将其删除,或者替代地不做任何事情,因为未使用的变量已被删除. (也许甚至不执行该方法;可以内联该方法,然后由于它没有执行任何操作,因此可以将其完全删除).

This is then turned into machine code. It would be analogous in how it would work in that it would either produce the number 5, store it locally (on the stack or in a register) and then get rid of it again, or alternatively do nothing because the unused variable has been removed. (Perhaps not even executing the method; the method could be inlined, and then since it doesn't do anything be effectively removed entirely).

对于带有构造函数的类型,还有更多的事情要做

With a type with a constructor, there's slightly more going on:

.method public hidebysig instance void myMethod () cil managed 
{
  .locals init ([0] class Temp.Program/Customer)       // Set-up space for a reference to a Customer

  nop                                                  // Do nothing.
  newobj instance void SomeNamespace/Customer::.ctor() // Call Customer constructor (results in Customer on the stack)
  stloc.0                                              // Store the customer in the frist slot in locals
  ret                                                  // Return
}

.method public hidebysig instance void myMethod () cil managed 
{
  newobj instance void SomeNamespace/Customer::.ctor() // Call Customer constructor (results in Customer on the stack)
  pop                                                  // Remove value from stack
  ret                                                  // Return
}

这里都调用了构造函数,甚至发布版本也这样做了,因为它必须确保仍然有任何副作用.

Here both call the constructor, and even the release build does that, because it has to ensure that any side-effects still happen.

如果Customer是引用类型,则还会发生更多事情.如果是值类型,则所有值都保存在堆栈中(尽管它可能又具有引用类型的字段).如果是引用类型,则堆栈中保存的是对堆中对象的引用.当堆栈上不再有任何此类引用时,垃圾收集器将不会在其扫描中找到它不能收集哪些对象,然后可以对其进行收集.

There is also more happening if Customer is a reference type. If it's a value-type then all of it is held in the stack (though it may have fields that are reference types in turn). If it's a reference type then what is held in the stack is a reference to an object in the heap. When there are no longer any such references on the stack the garbage collector won't find it in its sweep to find which objects it can't collect, and it can be collected.

在发行版中,构造函数返回后,可能永远不会有保存该引用的内存位置或寄存器.确实,即使构造函数正在运行(如果没有字段访问或 this 的其他隐式或显式使用)发生,也可能没有一个,或者它可能在此过程中被部分抹去了(一旦此类访问)已经完成),因此垃圾回收可能会在构造函数尚未完成之前进行.

In the release version, there might never be a memory location or register that holds that reference once the constructor returns. Indeed, there might not be one even when the constructor was running (if no field accesses or other implicit or explicit use of this happen) or it might have been wiped part-way through that (once such accesses had finished), so garbage collection could happen before the constructor has even finished.

该方法返回后,由于GC尚未运行,很有可能会在堆内存中徘徊一段时间.

More likely it will hang around in heap memory for some time after the method has returned, because the GC hasn't run yet.

这篇关于可变寿命的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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