2009-08-25 50 views
3

当我们传递一个值类型 - 已被存储在堆栈上 - 通过引用时,内存中会发生什么?通过引用传递'值类型'参考 - 内存占用

在方法完成时,必须在某处创建临时值/指针以更改原有值。有人可以请解释或指出我的答案 - 很多内存的东西,但似乎没有人回答这个问题。 ty

回答

4

如果你有这样的方法:

static void Increment(ref int value) 
{ 
    value = value + 1; 
} 

,并调用它像这样:

int value = 5; 
Increment(ref value); 

然后发生的事情是,而不是价值5堆栈上推时,变量value的位置被推入堆栈。即value的内容由Increment直接更改,而不是在方法完成后更改。

这里的方法的IL分别调用该方法:

.method private hidebysig static void Increment(int32& 'value') cil managed 
{ 
    .maxstack 8 
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldarg.0 
    L_0003: ldind.i4   // loads the value at the location of 'value' 
    L_0004: ldc.i4.1 
    L_0005: add 
    L_0006: stind.i4   // stores the result at the location of 'value' 
    L_0007: ret 
} 

.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    .maxstack 9 
    .locals init ([0] int32 value) // <-- only one variable declared 
    L_0000: nop 
    L_0001: ldc.i4.5 
    L_0002: stloc.0 
    L_0003: ldloca.s 'value' // call Increment with the location of 'value' 
    L_0005: call void Program::Increment(int32&) 
    L_000a: ret 
} 
+1

谢谢 - 所以一个指针是在堆栈上创建的值在堆栈上的位置...很酷!我希望调用堆栈能够准确显示内存中发生了什么。应该可能让我自己成为一个内存分析器。 – user10178 2009-08-25 18:08:09

+0

如果你对后台发生的事情感兴趣,总是值得看看编译器生成的IL。你可以使用.NET Reflector来反汇编你的程序集。 – dtb 2009-08-25 18:12:52

+0

我经常使用反射器,但尚未完全理解IL调用。我必须承认,由于某种原因,我没有想过在这里检查IL ...再次感谢。 – user10178 2009-08-25 18:17:30

0

听起来好像您正在寻找关于拳击和取消装箱的一些细节,这是用于描述将值类型作为参考类型进行处理的术语。

有很多描述过程的文章,我会尝试找到一些体面的文章 - but here's one for starters

+0

这里有一个答案,“为什么是装箱和拆箱不好?”它提供了对拳击/拆箱值类型的指针处理和性能命中的一些洞察:http://stackoverflow.com/questions/13055/what-is-boxing-and-unboxing-and-why-is-it-bad/ 25324#25324 – STW 2009-08-25 18:00:02