2009-08-24 31 views
7

Aquí mucha gente está confundida,¿Dónde almacena CLR las clases estáticas?

La clase normal almacena sus datos en el montón, ¿verdad? Y la referencia (Puntero) a la pila.

Cuando la pila cae fuera del alcance, la próxima vez que el recolector de basura se ponga en marcha y retire la memoria del montón.

Ahora en el caso de las clases estáticas, la memoria no puede ser limpiada por el recolector de basura porque debe estar ahí todo el programa. Y no hay forma de obtener la referencia en primer lugar.

Entonces cuando llamamos a la consola. Escribir, por ejemplo? ¿De dónde obtiene el programa su referencia desde (¿Dónde almacena la referencia a la clase estática)? O simplemente lo llama directamente, pero ¿cómo?

+4

No entiendo ninguna parte de esta pregunta. ¿Qué quiere decir con "su valor" y "su ref"? –

+0

Espero que esté hablando de cómo separa el código ejecutable de los miembros de datos. –

+1

Entre otros problemas, es "es". – jason

Respuesta

16

Creo que está confundiendo con clases donde la memoria vive con cómo la memoria se lleva a cabo en el. Cuando crea una instancia de una clase normal, la memoria de esa instancia vive en el montón. Una referencia a esta instancia podría estar en un objeto en el montón (si establece una variable miembro dentro de una instancia diferente de un objeto); o una variable de pila (si declaró una variable al objeto dentro de un método o la pasó a una llamada de función), o puede estar en la lista de raíces globales (si es una referencia estática, por ejemplo, una referencia Singleton).

No se puede crear una instancia de una clase estática. No hay "referencia" a la clase en ningún lado (a excepción de la información de tipo). Sus métodos son solo funciones cargadas en la memoria cuando el CLR carga el ensamblaje. Puede crear un delegado que apunte a uno de estos métodos, pero eso tampoco hace una referencia a una instancia de la clase. Eso es solo un puntero a una función.

Por ejemplo, un vistazo a este código:

class ObjectWrapper 
{ 
    Object obj = new Object(); 
} 

static void Main(string[] args) 
{ 
    ObjectWrapper wrapper = new ObjectWrapper(); 
    ... 
} 

el principal método crea una instancia de una clase ObjectWrapper. Esta instancia vive en el montón.

Dentro de la instancia de ObjectWrapper, hay una instancia de clase Object que vive en el montón. La referencia a esta clase está dentro de la instancia, así que supongo que podrías pensar en la referencia como "vivir en el montón".

Ahora, compare esto con el siguiente código:

class Singleton 
{ 
    static readonly instance = new Singleton(); 
} 

La instancia del objeto Singleton vive en el montón, también. Sin embargo, la referencia es una referencia estática. Lo mantiene el CLR en una lista de referencias globales o "raíz".

Ahora mira esta clase estática:

class ObjectWrapper 
{ 
    Object obj = new Object(); 
} 

static class HelperMethods 
{ 
    static int DoSomethingUseful(ObjectWrapper wrapper1) 
    { 
     ObjectWraper wrapper2 = wrapper1; 
     // code here 
    } 
} 

HelperMethods es una clase estática. No se puede crear una instancia de la clase HelperMethods. No puede haber ningún objeto de esta clase en el montón. Sin embargo, en el método DoSomethingUseful, tiene dos referencias a una instancia de la clase ObjectWrapper en la pila. Uno se pasa y uno se declara dentro del método.

+0

+1, disfruté de los detalles. – user7116

+0

En lo que respecta a "raíces", consulte este artículo que explica el algoritmo GC de .NET y aclara cómo las raíces tienen un papel en el GC. http://msdn.microsoft.com/en-us/magazine/bb985010.aspx – felideon

+0

Hay varios puntos en esta respuesta que no son del todo precisos. Por un lado, la afirmación 'No hay' referencia 'en ningún lado' es incorrecta. Una referencia a cada tipo, estática o no, se mantiene en un montón de carga. Todo el sistema de tipos se gestiona en un montón de cargadores, con referencias a tipos y sus miembros. Además, 'Esta clase nunca consumirá memoria en el montón' también es incorrecta ... mientras que no consume espacio de montón de GC, sí consume un montón de espacio en un montón de cargadores. La idea de una referencia simplemente como un puntero también es incorrecta ... la CLR usa muchos niveles de indirección. – jrista

6

Para darle una respuesta simple, las clases estáticas se "almacenan" en lo que se denomina un montón de carga.Los montones de cargadores son curaciones especiales que no son de GC y que tienen tasas de crecimiento extremadamente predecibles y estrictas. Cuando se inicia una aplicación .NET, en realidad se crean varios AppDomains. Además del dominio de aplicación principal, hay dominios de aplicaciones compartidas y de sistema que contienen los espacios de nombres del sistema y mscorelib, montones especiales (como los montones del cargador) y el propio CLR.

Para una explicación muy detallada, lea el siguiente artículo de MSDN Magazine:

Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects

A pesar de ser de unos pocos años atrás, todavía se aplica. (Sin embargo, no puedo decir si .NET 4.0 ha cambiado tanto.)

Cuestiones relacionadas