2012-02-14 18 views
5

Sto implementando la garbage collection mark-and-sweep in una semplice API di scripting su cui sto lavorando e sto leggendo su varie implementazioni della garbage collection. API come Lua usano il mark-and-sweep con liste bianche, grigie e nere.Perché bianco/grigio/nero in GC?

Il problema è che non riesco a trovare spiegazioni sul perché ci siano tali elenchi e sul perché siano inseriti in questi colori specifici.

Nella mia attuale, banale implementazione, uso semplicemente stati "morti" o "vivi". Nella spazzata, gli oggetti morti vengono cancellati. Sto usando l'heap nativo quindi non sto facendo alcun movimento nel mio GC.

sto scrivendo in C.

// Performs a full garbage collection 
void GorCollect(GorContext *ctx) 
{ 
    Value *v, *end; 
    Collectable *c, *n; 

    // mark stack references 
    end = ctx->stack + ctx->stackTop + 1; 
    v = ctx->stack; 
    while(v != end) 
    { 
     if (gvisgc(v) && v->v.gc) // mark if a collectable obj 
      Mark(v->v.gc); 
     v = v++; 
    } 

    // mark global references 
    if (ctx->global) 
     Mark((Collectable *)ctx->global); // ctx->global is a collectable obj 

    // perform sweep 
    c = ctx->gchead; // full list of collectable objs 
    ctx->gchead = 0; 
    while(c) { 
     n = c->next;  
     // destroy unmarked collectable 
     if (!c->marked) 
      FreeCollectable(ctx, c); 

     // rebuild gc list (singly-linked) 
     else 
     { 
      c->marked = 0; 
      if (!ctx->gchead) 
       c->next = 0; 
      else 
       c->next = ctx->gchead; 
      ctx->gchead = c; 
     } 
     c = n; 
    } 
} 
+0

'perché sono messi in questi colori specifici' - perché sono belli! – asaelr

+0

La ricerca di "mark and sweep white gray black" mi ha portato a: http://www.memorymanagement.org/glossary/t.html#tri-color.marking. Quella pagina fa notare che un'importante proprietà dell'algoritmo è "corretta", quindi la mia ipotesi sarebbe che l'approccio ingenuo abbia qualche limite in cui si rompe. – millimoose

+0

Inoltre: http://en.wikipedia.org/wiki/Mark_and_sweep#Naive_mark-and-sweep elenca come il principale svantaggio dell'approccio ingenuo che non può essere eseguito senza sospendere il processo. – millimoose

risposta

8

Grey significa "dal vivo, ma non sottoposto a scansione": non tutti i discendenti di un blocco grigio sono stati contrassegnati come nero ancora. Il colore grigio è necessario in un incrementale garbage collector. Aiuta un GC mark-and-sweep a continuare quello che stava facendo la prossima volta che ha la possibilità di fare un po 'di marcatura.

Se il tuo GC non è incrementale, potrebbe sembrare che non hai necessariamente bisogno del colore grigio: puoi semplicemente recitare sempre su tutti i bambini di qualsiasi blocco live che incontri. Tuttavia, un altro problema più sottile è che questo ingenuo algoritmo ricorsivo non incrementale può traboccare lo stack. Un colore grigio aiuta anche a memorizzare le informazioni su cosa visitare successivamente nell'heap, invece che nello stack.

Anche se si utilizza il colore grigio per questo scopo, non impedisce di mantenere un buffer di blocchi che rimangono da visitare per l'efficienza. L'unica differenza con l'implementazione ricorsiva ingenua è che si interrompe l'aggiornamento del buffer quando è già pieno e si esegue la scansione lineare dell'heap per gli oggetti grigi se il buffer si svuota dopo essere stato pieno.

+0

Sto cercando di capire come l'algoritmo può funzionare senza una scansione completa. Ciò che intendo è che se ho un oggetto aggregato contrassegnato come grigio, ma uno dei suoi oggetti figlio è contrassegnato come bianco, come evitare di dover attraversare l'intero albero per garantire che l'oggetto bianco non venga referenziato altrove. Non ha davvero senso come si possa farla franca senza analizzare l'intera gerarchia di riferimenti. A meno che la fase mark sia solo incrementale e che lo sweep debba essere eseguito una volta che il mark è stato completamente scansionato? In tal caso, dovresti gestire nuovi riferimenti tra marchi diversi. –

+0

"A meno che la fase di mark sia solo incrementale e lo sweep debba essere eseguito una volta che il mark è stato completamente scansionato?" Ovviamente, in un GC incrementale di mark-and-sweep l'algoritmo si alterna ancora tra una fase mark completa e una fase sweep completa. Ecco come funziona il mark-and-sweep. Credo che l'articolo "Uniprocessor Garbage Collection Techniques", di Paul Wilson, dovrebbe rispondere alle vostre domande. –

0

Prima di tutto, sono insiemi, non elenchi e ogni oggetto nell'heap è in qualsiasi momento esattamente in uno dei set.

In secondo luogo, in qualsiasi contrassegno & implementazione sweep vengono utilizzati, ma potrebbero essere implicita. Non si fornisce l'implementazione per Mark, ma in quella funzione si spostano gli oggetti nei propri set.

Ecco l'attuazione per la fase di marchio della mia garbage collector:

/* Initally, the white set contains all objects, the black and 
    grey sets are empty. */ 
stack *st = m->mark_stack; 
/* First all roots are added to the gray set. */ 
for (size_t i = 0; i < m->roots->used; i++) { 
    ptr p = m->roots->array[i]; 
    if (p != 0) { 
     /* Mark the root and move it to the gray set. */ 
     AT(p) |= 1; 
     st_push(st, p); 
    } 
} 
while (st->used) { 
    /* Think of popping the object from the mark stack as moving 
     it from the gray to the black set. */ 
    ptr p = st_pop(st); 
    P_FOR_EACH_CHILD(p, { 
     if (!GET_MARK(p_child)) { 
      /* Then mark each non-black child and move it to the 
       gray set. */ 
      AT(p_child) |= 1; 
      st_push(st, p_child); 
     } 
    }); 
} 
/* When control has reached this point, the gray set is empty and 
    the whole heap has been divided into black (marked) and white 
    (condemned) objects. */ 

Potremmo invece utilizzare le strutture di dati espliciti per i tre set. Ma per uno stop-the-world mark & sweep gc, questa implementazione è molto più efficiente.