2008-08-24 18 views
5
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:¿Cómo maneja la memoria gestionada .net los tipos de valores dentro de los objetos?

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

Aquí es mi pregunta:

  1. tipos de valor hacer dentro de los objetos viven en la pila o el montón?
  2. son los tipos del boxeo/unboxing valor de un objeto es una preocupación?
  3. ¿Hay algún detalle, sin embargo, los recursos 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 si tienen que estar en la caja para llegar allí.

Editar:

Lecturas sugeridas para este tema:

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

Respuesta

9

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 vive durante la duración de un método; ¿Cómo puede el valor persistir si solo existe dentro de esa pila?

El tamaño de un objeto de una clase en el montón administrado es la suma de sus campos de tipo valor, punteros de tipo de referencia y variables adicionales de CLR como el índice de 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.

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

public class EmbeddedValues 
{ 
    public int NumberField; 
} 

Y con ella, una clase de prueba simple.

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

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

Si utiliza el desensamblador de MSIL proporcionado por el .NET Framework SDK para echar un vistazo al 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 

Aviso el CLR se le dice a la stfld valor cargado de "20" en la pila en la ubicación del campo NumberField de EmbeddValues ​​cargado, directamente en el montón administrado. Del mismo modo, al recuperar el valor, utiliza ldfld instrucción para copiar directamente el valor de esa ubicación del montón administrado en la pila de subprocesos. Ninguna caja/unboxing ocurre con este tipo de operaciones.

2
  1. todas las referencias o los tipos de valor que poseen un objeto directo en el montón.
  2. Sólo si estás lanzando enteros a objetos.
2

El mejor recurso que he visto para esto es el libro CLR via C# de Jeffrey Richter. Vale la pena leerlo si haces cualquier desarrollo de .NET. Basado en ese texto, entiendo que los tipos de valores 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 desempaquetado no son simétricos. El boxeo puede ser una preocupación mayor que unboxing. Boxeo requiere copiar el contenido del tipo de valor de la pila al montón. Dependiendo de la frecuencia con la que esto le ocurra, no tiene sentido tener una estructura en lugar de una clase. Si tiene algún código de rendimiento crítico y no está seguro de si se está produciendo un boxeo y unboxing, use una herramienta para examinar el código IL de su método. Verá las palabras box y unbox en IL. Personalmente, mediría el rendimiento de mi código y solo luego vería si este es un candidato para preocuparse. En su caso, no creo que este sea un tema tan crítico. No tendrá que copiar de la pila al montón (recuadro) 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.

1

¿Los tipos de valores 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 los punteros para mantener referencias.

¿Son los tipos de valor de boxing/unboxing en un objeto una preocupación?

No hay boxeo aquí.

¿Existen recursos detallados pero comprensibles sobre este tema?

+1 voto para el libro de Richter.

2
  • Ans # 1: Heap. Parafraseando Don Box de su excelente 'Vol .Net esencial 1'

tipos de referencia (RT) siempre producen casos que se asignan en el montón. En contraste, los tipos de valor (VT) dependen del contexto: si una var local es una VT, la CLR asigna memoria a 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 qué campo se declara.

  • Respuesta # 2: Nº de boxeo sólo ocurriría cuando accede a una estructura a través de una referencia de objeto/puntero de interfaz. obInstance.VT_typedfield no se insertará.

    RT variables contiene la dirección del objeto al que se refiere. 2 RT var puede señalar el mismo objeto.En contraste, las variables de TV son las instancias mismas. 2 VT var no puede apuntar a un mismo objeto (struct)

  • Ans # 3: .NET esencial de Don Box/CLR de Jeffrey Richter a través de C#. Tengo una copia de la antigua ... aunque la tarde puede ser más actualizado para las revisiones .Net

0

Una variable u otra ubicación de almacenamiento de un tipo de estructura es una agregación de campos de instancia públicas y privadas de ese tipo. Dada

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

una declaración Foo bar; causará bar.x, bar.y y bar.z que se almacena allí donde bar se va a almacenar. Agregar una declaración de este tipo de bar a una clase será, desde una perspectiva de disposición de almacenamiento, equivalente a agregar tres campos int. De hecho, si uno nunca hizo nada con bar excepto el acceso de sus campos, los campos de bar se comportarían igual que haría con tres campos bar_x, bar_y y bar_cantaccessthis_z [acceder a la última requeriría hacer cosas con bar distinta de acceder a sus campos, pero ocuparía espacio si alguna vez se usa o no para nada].

El reconocimiento de las ubicaciones de almacenamiento de tipo estructura como agregaciones de campos es el primer paso para comprender las estructuras. Tratar de verlos como sosteniendo algún tipo de objeto puede parecer "más simple", pero no concuerda con cómo funcionan en realidad.

Cuestiones relacionadas