如何.NET托管内存句柄值类型中的对象?句柄、对象、内存、类型

2023-09-04 00:57:30 作者:殘花、已凋謝

 公共类MyClass的
{
    公众诠释年龄;
    公众诠释ID;
}

公共无效的MyMethod()
{
    MyClass的M =新MyClass的();
    INT NEWID;
}
 

据我了解,以下是正确的:

在该型号m住在堆栈上,并超出范围时的MyMethod()退出。 的值类型NEWID住在堆栈上,并超出范围时的MyMethod()退出。 由new操作符创建的对象住在堆和由GC变成可回收时的MyMethod()退出,假设没有其他的引用对象存在。

下面是我的问题:

请值类型中的对象居住在堆栈或堆?在 是拳击/拆箱值类型对象的关注? 是否有任何详细的,尚可以理解,资源这个主题吗?

从逻辑上讲,我倒是觉得里面的类值类型是在堆中,但我不知道他们是否有被装箱到那里。

编辑:

推荐阅读本主题:

CLR通过C#通过杰弗里里希特 由唐盒 基本.NET 解决方案

一类价值型值的有无的与托管堆中的对象实例一起生活。为一个方法的线程堆栈仅住一种方法的持续时间;如何能坚持的价值,如果它只有堆栈中存在?

.net内存分配

在托管堆中一个类的对象大小是它的值类型字段,引用类型的指针,以及额外的CLR开销变量,如同步块索引的总和。当一个分配一个值到一个对象的值型场中,CLR值拷贝到该particluar字段分配对象物的内部的空间中。

举个例子,一个简单的类有一个字段。

 公共类EmbeddedValues
{
  公众诠释NumberField;
}
 

有了它,一个简单的测试类。

 公共类EmbeddedTest
{
  公共无效TestEmbeddedValues​​()
  {
    EmbeddedValues​​ valueContainer =新EmbeddedValues​​();

    valueContainer.NumberField = 20;
    INT publicField = valueContainer.NumberField;
  }
}
 

如果您通过使用.NET Framework SDK中提供的MSIL反偷看IL $ C $下EmbeddedTest.TestEmbeddedValues​​()

 。方法公开hidebysig实例无效TestEmbeddedValues​​()CIL管理
{
  // code尺寸23(0x17已)
  .maxstack 2
  .locals的init([0]类soapextensions.EmbeddedValues​​ valueContainer,
           [1] INT32 publicField)
  IL_0000:NOP
  IL_0001:newobj实例无效soapextensions.EmbeddedValues​​ ::构造函数()。
  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
方法EmbeddedTest的} //结束:: TestEmbeddedValues
 

请注意,CLR被告知为 stfld 20在堆栈中加载EmbeddValues​​NumberField场的位置,装载值,直接进入托管堆。同样,检索值时,它使用的 ldfld 指令直接复制值指出,托管堆的位置进入线程堆栈。无盒/拆箱发生在这些类型的操作。

public class MyClass
{
    public int Age;
    public int ID;
}

public void MyMethod() 
{
    MyClass m = new MyClass();
    int newID;
}

To my understanding, the following is true:

The reference m lives on the stack and goes out of scope when MyMethod() exits. The value type newID lives on the stack and goes out of scope when MyMethod() exits. The object created by the new operator lives in the heap and becomes reclaimable by the GC when MyMethod() exits, assuming no other reference to the object exists.

Here is my question:

Do value types within objects live on the stack or the heap? Is boxing/unboxing value types in an object a concern? Are there any detailed, yet understandable, resources on this topic?

Logically, I'd think value types inside classes would be in the heap, but I'm not sure if they have to be boxed to get there.

Edit:

Suggested reading for this topic:

CLR Via C# by Jeffrey Richter Essential .NET by Don Box

解决方案

Value-type values for a class have to live together with the object instance in the managed heap. The thread's stack for a method only lives for the duration of a method; how can the value persist if it only exists within that stack?

A class' object size in the managed heap is the sum of its value-type fields, reference-type pointers, and additional CLR overhead variables like the Sync block index. When one assigns a value to an object's value-type field, the CLR copies the value to the space allocated within the object for that particluar field.

Take for example, a simple class with a single field.

public class EmbeddedValues
{
  public int NumberField;
}

And with it, a simple testing class.

public class EmbeddedTest
{
  public void TestEmbeddedValues()
  {
    EmbeddedValues valueContainer = new EmbeddedValues();

    valueContainer.NumberField = 20;
    int publicField = valueContainer.NumberField;
  }
}

If you use the MSIL Disassembler provided by the .NET Framework SDK to peek at the IL code for EmbeddedTest.TestEmbeddedValues()

.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

Notice the CLR is being told to stfld the loaded value of "20" in the stack to the loaded EmbeddValues' NumberField field location, directly into the managed heap. Similarly, when retrieving the value, it uses ldfld instruction to directly copy the value out of that managed heap location into the thread stack. No box/unboxing happens with these types of operations.