È noto che il garbage collector .NET non solo "elimina" gli oggetti nell'heap, ma combatte anche la frammentazione della memoria utilizzando la compattazione della memoria. Da quello che capisco, in pratica la memoria viene copiata in un nuovo posto, e il vecchio posto viene cancellato in qualche punto.In che modo il runtime .NET sposta la memoria?
La mia domanda è: come funziona?
Ciò di cui sono principalmente curioso è il fatto che il GC viene eseguito in un thread separato, il che significa che l'oggetto su cui stiamo lavorando può essere spostato dal GC mentre stiamo eseguendo il nostro codice.
dettagli tecnici della questione
Per illustrare, vorrei spiegare la mia domanda in modo più dettagliato:
class Program
{
private int foo;
public static void Main(string[] args)
{
var tmp = new Program(); // make an object
if (args.Length == 2) // depend the outcome on a runtime check
{
tmp.foo = 12; // set value ***
}
Console.WriteLine(tmp.foo);
}
}
In questo piccolo esempio, creiamo un oggetto e impostare una variabile semplice su un oggetto. Il punto '***' è tutto ciò che conta per la domanda: se l'indirizzo di 'tmp' si sposta, 'foo' farà riferimento a qualcosa di non corretto e tutto si spezzerà.
Il garbage collector viene eseguito in una thread separata. Quindi, per quanto ne so, 'tmp' può essere spostato durante questa istruzione e 'foo' può finire con il valore errato. Ma in qualche modo, la magia accade e non lo fa.
Per quanto riguarda il disassembler, ho notato che il programma compilato prende davvero l'indirizzo di 'foo' e si muove nel valore '12:
000000ae 48 8B 85 10 01 00 00 mov rax,qword ptr [rbp+00000110h]
000000b5 C7 40 08 0C 00 00 00 mov dword ptr [rax+8],0Ch
ho più o meno aspettavo di vedere un puntatore indiretta qui, che può essere aggiornato, ma a quanto pare il GC funziona meglio di così.
Inoltre, non vedo alcuna sincronizzazione del thread che controlli se l'oggetto è stato spostato. Quindi, come fa il GC ad aggiornare lo stato nel thread in esecuzione?
Quindi, come funziona? E se il GC non muove questi oggetti, qual è la 'regola' che definisce se no o meno spostare gli oggetti?
Si noti che le vecchie versioni di .NET utilizzavano un GC "stop-the-world", quindi i thread gestiti erano stati arrestati, GC era stato eseguito, i thread gestiti sono stati ripresi. – xanatos
Sei consapevole del fatto che il GC riprende i dati solo quando la tua istanza di 'Program' è fuori ambito? Quindi, finché la tua app è in esecuzione, avrai sempre un valore corretto per "pippo". – HimBromBeere