gpt4 book ai didi

c# - 局部变量实际上在 CLR 中分配在哪里?

转载 作者:太空狗 更新时间:2023-10-30 00:06:50 27 4
gpt4 key购买 nike

我刚刚进入 CLR 和 IL,我对这件事感到困惑。

我有以下 C# 代码:

int x = 1;
object obj = x;
int y = (int)obj;

IL 反汇编

      // Code size       18 (0x12)
.maxstack 1
.locals init ([0] int32 x,
[1] object obj,
[2] int32 y)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: unbox.any [mscorlib]System.Int32
IL_0010: stloc.2
IL_0011: ret

因此,ldloc.0 指令“将索引 0 处的局部变量加载到堆栈上。”。但是本地人真正存储在哪里,他们从哪里加载。因为我认为可以分配内存的地方有两个:线程栈和堆。并且变量应该存储在堆栈中。

现在,我想,堆栈只是一个“计算堆栈”,而变量的内存分配是一个实现细节,取决于平台和 JIT 编译器。我们实际上可以将程序使用的内存拆分为评估堆栈、托管堆和本地分配的内存。

这是真的吗?或者这里还有其他一些机制?

最佳答案

你严重混淆了许多逻辑上不同的事情:

  • 仅仅因为变量在 C# 中是局部变量并不意味着它在 IL 中位于短期存储池中。 C#中的局部变量可以对应相应IL中的短期存储、长期存储或计算栈。
  • IL 中的短期存储和评估堆栈可以对应于 jitted 机器代码中的堆栈或寄存器存储。

当将 C# 编译为 IL 时,C# 编译器使局部变量闭包类的成员——它们进入长期存储池——当局部变量的生命周期可能更长时 比激活方法。 (或者当方法的激活被分解成小块时,就像在异步方法中一样。)

如果局部变量的生命周期很短,那么编译器的优化器会选择它们是进入短期池还是评估堆栈;编译器称后者为“短暂的”本地人。决定何时将本地变为临时的算法很有趣;有关详细信息,请参阅编译器源代码。

然后抖动必须决定是否将短期池变量和评估堆栈变量放入堆栈位置或寄存器;它使用复杂的优化算法再次这样做,该算法根据寄存器可用性等而有所不同。

最后,当然,C# 编译器和抖动都可以自由地将未读本地具体化为一无所有;从未被读取的存储实际上不需要分配。

关于c# - 局部变量实际上在 CLR 中分配在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47520657/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com