我对如何在.NET中以内存方式管理ValueType
对象感到困惑。我得到的值类型被放在每个实例/声明的堆栈上。我不太清楚什么构成了新的实例/声明。我认为我的主要问题是:
ValueType
参数传递给方法,但是没有为其赋值,那么是否是在堆栈上创建的新实例?我不确定我是否正确地说这个,所以我写了一个简单的示例程序,以便更容易理解我的困惑。
void Main()
{
//-------------------------| Line 1:
int MichaelJordan = 23;
//-------------------------| Line 2:
int HoursInADay = 24;
//-------------------------| Line 3:
Console.WriteLine("Michael Jordan is "+(NumberHelper.Is23(MichaelJordan) ? string.Empty : "not ")+"23");
//-------------------------| Line 4:
Console.WriteLine("The last number that wasn't 23 was "+NumberHelper.LastNumberThatWasnt23);
//-------------------------| Line 5:
Console.WriteLine("Hours in a Day is "+(NumberHelper.Is23(HoursInADay) ? string.Empty : "not ")+"23");
//-------------------------| Line 6:
Console.WriteLine("The last number that wasn't 23 was "+NumberHelper.LastNumberThatWasnt23);
}
public static class NumberHelper {
public static int LastNumberThatWasnt23;
public static bool Is23(int candidate){
if(candidate != 23){
LastNumberThatWasnt23 = candidate;
return false;
}
return true;
}
}
此程序在堆栈上创建了多少个整数实例?
在代码中,确切地说,是在堆栈上创建的每个值类型实例?
第1行:我知道在堆栈上为变量MichaelJordan
创建了一个新实例
第2行:我知道在堆栈上为变量HoursInADay
创建了一个新实例
第3行:是在变量MichaelJordan
中创建的值实例的副本
为了成为方法参数?是否为比较创建了值23
的实例?
第4行: LastNumberThatWasnt23
字段的值未初始化,因此返回默认值。是否为此字段创建了默认值的新实例?
第5行:与第3行相同的问题,但是,我知道在字段LastNumberThatWasnt23
的堆栈上创建了一个新实例,因为我正在设置它。
第6行:现在,该字段有一个值。但是,在引用该值并将其传递到Console.WriteLine
方法时,我是否在堆栈上创建了一个新的值实例?
我还有一个问题,那就是我怎样才能找到这样的东西?我可以通过编程方式进行吗?是否有任何工具可用于揭示此类信息?
我知道这是一个很长的问题,所以我感谢您花时间阅读它。
答案 0 :(得分:3)
这取决于您的机器用于运行此程序的抖动。但由于您只使用两个局部变量,因此正确答案很可能为零。 jit优化器将变量值存储在CPU寄存器中。这是标准优化之一。
您可以找到有关抖动在this answer中执行的优化类型的更多信息。
答案 1 :(得分:2)
这很复杂。抖动是允许几乎自由的统治。它可以将局部变量放入寄存器,堆栈或两者,或者首先放在一个寄存器中。局部变量和堆栈分配之间没有简单的对应关系。
你可以通过反汇编asm代码(而不是IL)找到那些东西。即使这样,它依赖于编译标志,调试器的存在,方法的确切内容,.net版本......
但为什么一点都重要?局部变量消耗的堆栈内存可以忽略不计,除非你非常深入地进行递归。
答案 2 :(得分:1)
memory allocation of value types and reference types in .net framework应该回答大多数(如果不是全部)问题。