2009-08-24 22 views
7

Qui un sacco di persone sono confuse,Dove archivia CLR le classi statiche?

La classe normale memorizza i suoi dati nello heap giusto? E il riferimento (puntatore) allo stack.

Quando lo stack non rientra nell'ambito, la prossima volta che il garbage collector prende il via e rimuove la memoria dall'heap.

Ora in caso di classi statiche, la memoria non può essere pulita dal garbage collector perché deve essere lì l'intero programma. E non c'è modo di ottenere il riferimento in primo luogo.

Quindi quando chiamiamo Console. Scrivi, per esempio? Da dove prende il riferimento il programma (Dove memorizza il riferimento alla classe statica)? O lo chiama direttamente, ma come?

+4

Non capisco nessuna parte di questa domanda. Cosa intendi con "il suo valore" e "il suo riferimento"? –

+0

Mi aspetto che parli di come separa il codice eseguibile dai membri dei dati. –

+1

Tra le altre questioni, è "la sua". – jason

risposta

16

penso che sei classi confuse con dove la memoria vive con come la memoria si tiene a. Quando crei un'istanza di una classe normale, la memoria di quell'istanza risiede nell'heap. A il riferimento a questa istanza potrebbe trovarsi in un oggetto sull'heap (se si imposta una variabile membro all'interno di un'istanza diversa di un oggetto); o una variabile stack (se hai dichiarato una variabile per l'oggetto all'interno di un metodo o l'hai passata a una chiamata di funzione), o potrebbe essere nell'elenco di root globali (se si tratta di un riferimento statico, ad esempio un riferimento Singleton).

Una classe statica non può essere istanziata. Non esiste alcun "riferimento" alla classe in nessun luogo (eccetto per le informazioni sul tipo). I suoi metodi sono solo funzioni caricate in memoria quando il CLR carica l'assembly. È possibile creare un delegato che punti a uno di questi metodi, ma che non fa riferimento a un'istanza della classe. Questo è solo un puntatore a una funzione.

Per esempio, un'occhiata a questo codice:

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

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

Il metodo principale crea un'istanza di una classe ObjectWrapper. Questa istanza vive nell'heap.

Dentro l'istanza ObjectWrapper, c'è un'istanza della classe Object che vive sul mucchio. Il riferimento a questa classe è all'interno dell'istanza, quindi penso che potresti pensare al riferimento come "vivere nell'heap".

Ora, confronta al seguente codice:

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

L'istanza dell'oggetto Singleton vive sul mucchio, anche. Tuttavia, il riferimento è un riferimento statico. È gestito dal CLR in un elenco di riferimenti globali o "root".

Ora un'occhiata a questa classe statica:

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

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

HelperMethods è una classe statica. Non è possibile creare un'istanza della classe HelperMethods. Non ci possono essere oggetti da questa classe sull'heap. Tuttavia, nel metodo DoSomethingUseful, ha due riferimenti a un'istanza della classe ObjectWrapper in pila. Uno viene passato e uno viene dichiarato all'interno del metodo.

+0

+1, apprezzato il dettaglio. – user7116

+0

Per quanto riguarda le "radici", consulta questo articolo che spiega l'algoritmo GC di .NET e chiarisce in che modo le radici hanno un ruolo nel GC. http://msdn.microsoft.com/en-us/magazine/bb985010.aspx – felideon

+0

Ci sono diversi punti in questa risposta che non sono completamente accurati. Per uno, l'affermazione "Non c'è" riferimento "ovunque" non è corretta. Un riferimento a ogni tipo, statico o meno, è contenuto in un heap del caricatore. L'intero sistema di tipi viene gestito su un heap del caricatore, con riferimenti a tipi e ai relativi membri. Inoltre, "questa classe non consumerà mai memoria nell'heap" è anch'essa errata ... mentre non consuma spazio dell'heap GC, essa consuma spazio su un heap del caricatore. Anche l'idea di un riferimento che è semplicemente un puntatore è errata ... il CLR utilizza molti livelli di riferimento indiretto. – jrista

6

di darvi una risposta semplice, classi statiche vengono "immagazzinati" su quello che viene chiamato un Loader Heap.Gli heap del caricatore sono cure speciali e non GC con tassi di crescita estremamente prevedibili e rigidi. All'avvio di un'applicazione .NET, vengono creati diversi AppDomain. Oltre al dominio dell'app principale, esistono domini di app di sistema e condivisi che contengono gli spazi dei nomi di sistema e mscorelib, gli heap speciali (come gli heap del caricatore) e lo stesso CLR.

Per una spiegazione completa e dettagliata, leggere il seguente articolo di MSDN Magazine:

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

Pur essendo da pochi anni fa, si applica ancora. (Tuttavia, non posso dire se .NET 4.0 è cambiato molto.)

Problemi correlati