public class MyClass
{
public int Age;
public int ID;
}
public void MyMethod()
{
MyClass m = new MyClass();
int newID;
}
据我了解,以下情况属实:
- 引用 m 存在于堆栈中,并在 MyMethod() 退出时超出范围。
- 值类型 newID 存在于堆栈中,并在 MyMethod() 退出时超出范围。
- 由 new 运算符创建的对象位于堆中,并且当 MyMethod() 退出时,可以由 GC 回收(假设不存在对该对象的其他引用)。
这是我的问题:
- 对象中的值类型位于堆栈还是堆上?
- 对象中的装箱/拆箱值类型是否值得关注?
- 有关于这个主题的详细且易于理解的资源吗?
从逻辑上讲,我认为类内的值类型应该在堆中,但我不确定它们是否必须装箱才能到达那里。
Edit:
本主题的建议阅读:
- 通过 C# 进行 CLR 作者:Jeffrey Richter
- Don Box 的 Essential .NET
类的值类型值have与托管堆中的对象实例一起生活。方法的线程堆栈仅在方法的持续时间内存在;如果该值仅存在于该堆栈中,那么该值如何持久存在?
托管堆中类的对象大小是其值类型字段、引用类型指针以及其他 CLR 开销变量(例如同步块索引)的总和。当将值分配给对象的值类型字段时,CLR 会将值复制到对象内为该特定字段分配的空间。
以具有单个字段的简单类为例。
public class EmbeddedValues
{
public int NumberField;
}
随之而来的是一个简单的测试类。
public class EmbeddedTest
{
public void TestEmbeddedValues()
{
EmbeddedValues valueContainer = new EmbeddedValues();
valueContainer.NumberField = 20;
int publicField = valueContainer.NumberField;
}
}
如果您使用.NET Framework SDK提供的MSIL反汇编器来查看EmbeddedTest.TestEmbeddedValues()的IL代码
.method public hidebysig instance void TestEmbeddedValues() cil managed
{
// Code size 23 (0x17)
.maxstack 2
.locals init ([0] class soapextensions.EmbeddedValues valueContainer,
[1] int32 publicField)
IL_0000: nop
IL_0001: newobj instance void soapextensions.EmbeddedValues::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s 20
IL_000a: stfld int32 soapextensions.EmbeddedValues::NumberField
IL_000f: ldloc.0
IL_0010: ldfld int32 soapextensions.EmbeddedValues::NumberField
IL_0015: stloc.1
IL_0016: ret
} // end of method EmbeddedTest::TestEmbeddedValues
请注意 CLR 被告知stfld将堆栈中加载的值“20”加载到加载的 EmbeddValues 的 NumberField 字段位置,直接进入托管堆。同样,在检索值时,它使用ldfld指令直接将值从托管堆位置复制到线程堆栈中。这些类型的操作不会发生装箱/拆箱。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)