2010-08-22 12 views
10

durante la lettura di "C# in Depth" Stavo passando attraverso la sezione "Tipi di riferimento in diretta sull'heap, i tipi di valore in diretta nello stack".I tipi di riferimento in diretta sullo heap, i tipi di valore in diretta sullo stack

Ora quello che ho potuto capire è (principalmente per il tipo ref):

class Program 
{ 
    int a = 5; // stored in heap 

    public void Add(int x, int y) // x,y stored in stack 
    { 
     int c = x + y; // c stored in stack 
    } 
} 

Voglio solo chiarire se le mie ipotesi sono di destra. Grazie. EDIT: Avrei dovuto usare variabili diff, penso che abbia creato una confusione.so Ho modificato il codice.

EDIT: Sì, come detto Jon - scuse that.My è un mito, Avrei detto.

risposta

13

http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

l'intero "tipi di riferimento sul mucchio, i tipi di valore nello stack" non è solo un brutto modo di vedere le cose, ma è troppo male.

+0

può u pls modificare il codice e explain- voglio dire un esempio di tipo valore memorizzato in mucchio – Wondering

+0

Non c'è niente da modificare. Nel tuo codice, a è già memorizzato nell'heap come parte dell'oggetto Program. – siride

+0

quindi, vuoi dire che le mie supposizioni sono giuste. – Wondering

1

c lascia sullo stack perché almeno è un tipo di valore nel frattempo a nel mucchio gestito a causa di essere il campo del tipo di riferimento

+1

Nota che il valore di 'C' sarebbe sullo stack (nelle implementazioni correnti), anche se fosse di tipo (diciamo)' StringBuilder'. È solo che il valore della variabile sarebbe un riferimento a un oggetto - è l'oggetto * che si troverà nell'heap. Trovo molte cose sono più chiare, una volta a distinguere tra una variabile, il suo valore, e ciò che questo valore rappresenta in realtà (per esempio un riferimento piuttosto che un oggetto reale). –

+0

@Jon: Grazie per questa nota! – abatishchev

8

Posso essere un po 'utile un'astrazione di avere un'immagine mentale di quello che sta succedendo dietro la scene. Ma nessuno dei due è vero in nessuna versione attualmente in commercio dei compilatori JIT. Quale forse è il nodo del problema, la posizione di allocazione effettiva è un dettaglio di implementazione del compilatore JIT.

Ci sono almeno sei luoghi in cui un valore di tipo valore può convivere tradizionale (x86 e x64) nervosismo:

  • in uno stack frame, messo lì da una dichiarazione variabile locale o una chiamata metodo
  • in un registro CPU, un'ottimizzazione molto comune eseguita dal JIT nella build Release. E usato per passare argomenti ad un metodo, i primi due x86, quattro per x64. E variabili locali quando possibile
  • in pila FPU, utilizzati dal jitter x86 per virgola mobile valori
  • sul mucchio GC, quando il valore è parte di un tipo di riferimento
  • sul mucchio pala del AppDomain, quando la variabile è dichiarata statica
  • nella memoria locale del thread quando la variabile ha l'attributo [ThreadStatic].

Gli oggetti del tipo di riferimento sono comunemente allocati nell'heap del GC. Ma so di un'eccezione specifica, le stringhe internate prodotte da letterali nel codice sorgente sono allocate nell'heap del caricatore di AppDomain. Questo comportamento si comporta completamente come un oggetto in fase di runtime, tranne per il fatto che non è collegato all'heap GC, ma semplicemente il collector non può vederlo.

Affrontare il tuo frammento di codice:

  • sì "a" è probabile essere memorizzati sul mucchio GG
  • "x" viene sempre passato in un registro della CPU x86 e x64. "y" sarà in un registro CPU su x64, lo stack su x86.
  • "c" probabilmente non esiste affatto, rimosso dal compilatore JIT perché il codice non ha alcun effetto.
+0

Perché prima param 'x' sarà in pila e secondo' y' - non sempre? Post scriptum 'C' verrà rimosso nella modalità di rilascio – abatishchev

+0

Due registri CPU per un nucleo 86, quattro per un nucleo x64. Il "questo" puntatore richiede uno. –

0

Le posizioni di memoria (variabili, campi, elementi di matrice, ecc.) Dei tipi di riferimento contengono riferimenti agli oggetti nell'heap; le posizioni di stoccaggio dei tipi di valore primitivi mantengono il loro valore dentro di sé; Le posizioni di archiviazione dei tipi di struttura contengono tutti i loro campi, ognuno dei quali può essere un riferimento o un tipo di valore, all'interno di essi. Se un'istanza di classe contiene due diverse stringhe non nulle, un Punto e un intero, entrambe le coordinate X e Y del punto, nonché il numero intero autonomo e i riferimenti alle due stringhe, verranno mantenute all'interno di un heap oggetto. Ciascuna stringa verrà conservata in un oggetto heap diverso. Il punto chiave sulla posizione di classi contro le strutture di memorizzazione è che, salvo nel caso di un'entità classe possesso di un riferimento ad essa, ogni non nullo campo tipo di riferimento all'interno di una classe o struct terrà un riferimento a qualche altro oggetto, che sarà sul mucchio.

0

pensare in termini C/C++.

Ogni volta che si crea qualcosa di "nuovo", o si usa malloc, che va nell'heap-- cioè, "l'oggetto" va sull'heap, il puntatore stesso viene posto nello stack nell'ambito della struttura (o funzione, che è in realtà solo un'altra struttura) di cui fa parte. Se è una variabile locale o un tipo di riferimento (puntatore), va in pila.

Per dirla in un altro modo, l'oggetto> < a cui punta il tipo di riferimento è nell'heap, è solo il puntatore stesso che è nello stack. Perdite di memoria si verificano quando il programma fa uscire il puntatore dallo stack, ma la memoria nell'heap non è stata liberata per l'uso: come fai a sapere quale memoria liberarla se il riferimento alla sua posizione è stato perso? Bene, C/C++ non poteva, dovevi farlo tu stesso prima che il riferimento venisse estratto dallo stack e perso per sempre, ma è qui che le lingue moderne arrivano con i loro fantasiosi "cumuli di garbage collection". È comunque preferibile pulire in modo esplicito qualsiasi memoria heap allocata rispetto a quella implicita lasciandola per il ritiro del GC, in questo modo è "più economica" (in termini di risorse della CPU).

0

Citando Jon Skeet dalla sua famous blog su come e dove tipi di riferimento e valore sono caricate in un'applicazione Net:

Lo slot di memoria per una variabile è memorizzato su entrambi stack o mucchio. Dipende dal contesto in cui viene dichiarata:

  1. Ogni variabile locale (ovvero dichiarata in un metodo) viene memorizzata nello stack. Che include variabili di tipo riferimento - la variabile stessa è in pila, ma ricordate che il valore di un tipo di riferimento variabile è soltanto un riferimento (o nullo), non l'oggetto stesso. Metodo parametri contano come variabili locali troppo, ma se sono dichiarate con il modificatore ref, non ottengono il loro alloggiamento, ma condividono una slot machine con la variabile utilizzata nel codice chiamante. Vedi il mio articolo sul parametro passando per maggiori dettagli.
  2. Le variabili di istanza per un tipo di riferimento sono sempre nell'heap. È lì che l'oggetto stesso "vive".
  3. variabili istanza per un tipo di valore sono memorizzati nello stesso contesto come variabile che dichiara il tipo di valore. Lo slot di memoria per l'istanza contiene effettivamente gli slot per ciascun campo all'interno dell'istanza . Che mezzi (dato i precedenti due punti) che una variabile struct dichiarata all'interno di un metodo sarà sempre in pila, mentre una variabile struct che è un campo istanza di una classe sarà sulla mucchio.
  4. Ogni variabile statica viene archiviata nell'heap, indipendentemente dal fatto che sia dichiarata all'interno di un tipo di riferimento o di un tipo di valore. C'è solo lo uno slot in totale, indipendentemente dal numero di istanze create. (Ci non hanno bisogno di essere tutte le istanze create per questo uno slot di esistere però.) I dettagli di esattamente quali heap le variabili vivono sono complicato, ma spiegato in dettaglio in un articolo di MSDN sul soggetto.
Problemi correlati