¿Cómo maneja la memoria administrada .net los tipos de valor dentro de los objetos?

StackOverflow https://stackoverflow.com/questions/24829

  •  09-06-2019
  •  | 
  •  

Pregunta

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

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

A mi entender, lo siguiente es cierto:

  1. La referencia m vive en la pila y queda fuera del alcance cuando MyMethod () sale.
  2. El tipo de valor newID vive en la pila y queda fuera del alcance cuando MyMethod () sale.
  3. El objeto creado por el nuevo operador vive en el montón y se vuelve reclamable por el GC cuando MyMethod () sale, suponiendo que no existe ninguna otra referencia al objeto.

Aquí está mi pregunta:

  1. ¿Los tipos de valor dentro de los objetos viven en la pila o en el montón?
  2. ¿Los tipos de valores de boxeo / unboxing en un objeto son una preocupación?
  3. ¿Existen recursos detallados pero comprensibles sobre este tema?

Lógicamente, creo que los tipos de valor dentro de las clases estarían en el montón, pero no estoy seguro de que deban ser encajonados para llegar allí.

Editar:

Lectura sugerida para este tema:

  1. CLR Via C # por Jeffrey Richter
  2. Essential .NET by Don Box
¿Fue útil?

Solución

Los valores de tipo de valor para una clase tienen para vivir junto con la instancia del objeto en el montón administrado. La pila del hilo para un método solo dura la duración de un método; ¿cómo puede persistir el valor si solo existe dentro de esa pila?

El tamaño del objeto de una clase en el montón administrado es la suma de los campos de tipo de valor, los punteros de tipo de referencia y las variables de sobrecarga de CLR adicionales, como el índice del bloque de sincronización. Cuando uno asigna un valor al campo de tipo de valor de un objeto, el CLR copia el valor al espacio asignado dentro del objeto para ese campo particular.

Tomemos, por ejemplo, una clase simple con un solo campo.

public class EmbeddedValues
{
  public int NumberField;
}

Y con él, una clase de prueba simple.

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

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

Si usa el Desensamblador MSIL provisto por el SDK de .NET Framework para ver el código IL para 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

Observe que se le indica a CLR que stfld el valor cargado de " 20 " en la pila a la ubicación del campo NumberField de los valores de incrustación cargados, directamente en el montón administrado. De manera similar, cuando recupera el valor, usa la instrucción ldfld para copiar directamente el valor fuera de la ubicación del montón gestionado en la pila de hilos. Ninguna caja / unboxing ocurre con estos tipos de operaciones.

Otros consejos

  1. Todas las referencias o tipos de valor que posee un objeto viven en el montón.
  2. Solo si estás lanzando ints a objetos.

El mejor recurso que he visto para esto es el libro CLR a través de C # por Jeffrey Richter. Vale la pena leerlo si haces cualquier desarrollo .NET. Según este texto, entiendo que los tipos de valor dentro de un tipo de referencia viven en el montón incrustado en el objeto principal. Los tipos de referencia son siempre en el montón. El boxeo y el unboxing no son simétricos. El boxeo puede ser una preocupación más grande que unboxing. El boxeo requerirá copiar el contenido del tipo de valor de la pila al montón. Dependiendo de la frecuencia con que esto le suceda, puede que no tenga sentido tener una estructura en lugar de una clase. Si tiene algún código crítico de rendimiento y no está seguro de si está ocurriendo el boxeo y el desempaquetado, use una herramienta para examinar el código IL de su método. Verás el cuadro de palabras y unbox en el IL. Personalmente, mediría el rendimiento de mi código y solo entonces vería si este es un candidato para preocuparse. En su caso, no creo que este sea un problema tan crítico. No tendrá que copiar de la pila al montón (cuadro) cada vez que acceda a este tipo de valor dentro del tipo de referencia. Ese escenario es donde el boxeo se convierte en un problema más significativo.

  • Ans # 1: Heap. Parafraseando a Don Box desde su excelente 'Essential .Net Vol 1'
  

Los tipos de referencia (RT) siempre producen instancias que se asignan en el montón. En contraste, los tipos de valor (VT) dependen del contexto: si una var local es un VT, el CLR asigna memoria en la pila. Si un campo en una clase es miembro de un VT, entonces el CLR asigna memoria para la instancia como parte del diseño del objeto / tipo en el que se declara el campo.

  • Respuesta n. ° 2: No. El boxeo solo ocurriría cuando acceda a una estructura a través de una Referencia de objeto / Puntero de interfaz. obInstance.VT_typedfield no encajará.

      

    Las variables RT contienen la dirección del objeto al que hace referencia. 2 RT var puede apuntar al mismo objeto. En contraste, las variables VT son las instancias mismas. 2 VT var no puede apuntar al mismo objeto (estructura)

  • Respuesta n. ° 3: CLR .net de Don Box / CLR de Jeffrey Richter a través de C #. Tengo una copia de la primera ... aunque la última puede estar más actualizada para las revisiones de .Net

  

¿Los tipos de valor dentro de los objetos viven en la pila o en el montón?

En el montón. Son parte de la asignación de la huella del objeto, al igual que lo serían los punteros para contener referencias.

  

¿Los tipos de valor de boxeo / unboxing en un objeto son una preocupación?

No hay boxeo aquí.

  

¿Hay recursos detallados pero comprensibles sobre este tema?

+1 vota por el libro de Richter.

Una ubicación de almacenamiento variable u otra de un tipo de estructura es una agregación de los campos de instancia pública y privada de ese tipo. Dado

struct Foo {public int x,y; int z;}

una declaración Foo bar; causará bar.x , bar.y y bar.z se almacenará donde sea que se va a almacenar bar . Agregar dicha declaración de barra a una clase será, desde una perspectiva de diseño de almacenamiento, equivalente a agregar tres campos int . De hecho, si uno nunca hizo nada con bar , excepto el acceso a sus campos, los campos de bar se comportarían igual que tres campos bar_x , < code> bar_y , y bar_cantaccessthis_z [acceder a la última requeriría hacer cosas con la barra además de acceder a sus campos, pero ocuparía espacio si siempre se usa para cualquier cosa].

Reconocer las ubicaciones de almacenamiento de tipo estructura como agregaciones de campos es el primer paso para comprender las estructuras. Tratar de verlos como la celebración de algún tipo de objeto puede parecer " más simple " ;, pero no coincide con su funcionamiento real.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top