Come fa un garbage collector concorrente a gestire le variabili?

8

Diciamo che è un garbage collector simultaneo mark-and-sweep.

Quando tale GC gestisce puntatori costanti, li attraversa (iniziando dalle radici) e contrassegna tutti i blocchi di dati rilevati. Quindi spazza tutto senza segno. Un codice client deve contrassegnare i blocchi di dati che utilizza come root.

Ma cosa fare con le variabili? Ecco una situazione:

  1. V è una variabile, che memorizza un puntatore all'oggetto A .
  2. Thread 1 legge V e sospende.
  3. Thread 2 modifica V e fa puntare all'oggetto B .
  4. Il garbage collector esegue la sua fase di "mark" e rileva che A non viene più referenziato, quindi lo rilascia durante la fase di "sweep".
  5. Thread 1 si sveglia e tenta di utilizzare A (già letto da V al passaggio 2) contrassegnandolo come root. E fallisce , perché A non esiste più.

Quindi, come gestirlo?

Il Thread 2 può contrassegnare l'oggetto sostituito A con uno speciale flag di non rimozione (il flag simile è usato per gli oggetti appena assegnati). Ma quando questa bandiera dovrebbe essere rimossa? Ovviamente Thread 1 potrebbe farlo. Ma Thread 2 non sa nulla di Thread 1 , e quindi non può essere sicuro che questo verrà fatto sempre. Questo potrebbe portare a A non verrà mai liberato. E se GC rimuoverà quel contrassegno, nulla impedisce che A venga rimosso quando GC viene eseguito per la seconda volta ...

Le descrizioni dei garbage collector mark-and-sweep al volo che ho letto ricordano solo che l'oggetto sostituito dovrebbe essere "grigio". Ma senza dettagli. Un link ad una descrizione più dettagliata della soluzione sarebbe molto apprezzato.

    
posta lorus 06.03.2013 - 04:39
fonte

2 risposte

4

A seconda dei dettagli precisi dell'implementazione del garbage collector, questo potrebbe non essere affatto un problema nel passaggio 4. Ad esempio, nel passaggio 2, il thread 1 legge presumibilmente V in un registro. Il garbage collector avrà probabilmente bisogno di esaminare il contenuto dei registri per tutti i thread attivi (in esecuzione e sospesi) per vedere se c'è un riferimento a qualsiasi oggetto contenuto nei registri.

Inevitabilmente, un'implementazione di Garbage Collector è strettamente accoppiata all'ambiente operativo (e di threading) in cui viene eseguita. Esistono molte tecniche di implementazione per garantire che tutti i riferimenti memorizzati e transitori siano considerati.

    
risposta data 06.03.2013 - 04:53
fonte
0

Devi segnare le variabili locali qualche volta durante la fase mark. Tutte le variabili locali, comprese quelle che normalmente vivono in pila. In qualche modo.

Penso inoltre che debba essere fatto durante la fase sincrona (tutti i mutatori fermati) di scansione degli oggetti modificati. In effetti, lo stesso problema potrebbe sorgere anche senza considerare variabili / registri locali. Considera l'oggetto A che punta a null e l'oggetto B che punta a C. Ora esegui la scansione dell'oggetto A, viene un thread mutatore, copia il riferimento a C da B a A, elimina B e ora vai in giro a scansione B. E C scivola sotto le dita.

Non conosco alcun modo per occuparmi di ciò che non implichi l'arresto dei mutatori. La solita tecnica è alla fine della fase di mark per fermare tutti i mutatori e ri-marcare tutti gli oggetti che hanno mutato durante la fase di marcatura principale. E includere stack e registri in questo.

Normalmente i registri di marcatura vengono aggirati facendolo in modo sincrono chiamando a volte il raccoglitore nel thread. All'interno della funzione collector, solo le proprie variabili locali (che non sono root) possono essere nei registri, tutte le altre variabili locali nella catena di chiamate sono in pila, quindi puoi camminare nello stack.

In alternativa puoi inviare un segnale alla discussione. Il gestore del segnale forza nuovamente tutte le variabili sullo stack, così puoi camminarle. Lo svantaggio di questo metodo è che dipende dalla piattaforma.

    
risposta data 06.03.2013 - 09:15
fonte

Leggi altre domande sui tag