2011-01-11 4 views
12

Quali sono le differenze tra i puntatori condivisi (come boost :: shared_ptr o il nuovo std :: shared_ptr) e i metodi di raccolta dei rifiuti (come quelli implementati in Java o C#)? Per come la capisco, i puntatori condivisi tengono traccia di quante volte le variabili puntano alla risorsa e automaticamente distruggono la risorsa quando il conteggio raggiunge lo zero. Tuttavia, la mia comprensione è che il garbage collector gestisce anche le risorse di memoria, ma richiede risorse aggiuntive per determinare se un oggetto è ancora riferito e non necessariamente distrugge immediatamente la risorsa.Garbage Collection e puntatori condivisi

Sono corretto nelle mie ipotesi e ci sono altre differenze tra l'uso di garbage collector e i puntatori condivisi? Inoltre, perché mai qualcuno avrebbe mai usato un garbage collector su un puntatore condiviso se svolgevano attività simili ma con valori prestazionali variabili?

+1

L'utilizzo di puntatori condivisi ** è ** una tecnica di garbage collection. Molti garbage collector implementano, almeno come primo passo, il conteggio dei riferimenti. –

risposta

12

La differenza principale risiede, come hai notato, nel momento in cui la risorsa viene rilasciata/distrutta.

Un vantaggio in cui un GC potrebbe rivelarsi utile se si dispone di risorse che richiedono molto tempo per essere rilasciate. Per un breve ciclo di vita del programma, potrebbe essere utile lasciare le risorse penzoloni e ripulirle alla fine. Se vengono raggiunti limiti di risorse, il GC può agire per rilasciare alcuni di essi. I puntatori condivisi, d'altra parte, rilasciano le loro risorse non appena il conteggio dei riferimenti raggiunge lo zero. Questo potrebbe essere costoso per i frequenti cicli di acquisizione-rilascio di una risorsa con requisiti di tempo costosi.

D'altra parte, in alcune implementazioni di garbage collection, la garbage collection richiede che l'intero programma sospenda l'esecuzione mentre la memoria viene esaminata, spostata e liberata. Esistono implementazioni più intelligenti, ma nessuna è perfetta.

+4

Ci sono garbage collector senza priorità, incrementali e simultanei che non richiedono che il mutatore venga interrotto dal collector.Inoltre, come dimostra la letteratura, i garbage collector generalmente hanno un rendimento migliore del conteggio di riferimento nel tipico mutatore. –

15

Questi puntatori condivisi (di solito denominati conteggio di riferimento) corrono il rischio di cicli.

La garbage collection (Mark and Sweep) non presenta questo problema.

+0

potresti spiegare cosa intendi per "rischio di cicli"? Intendi che il conteggio dei riferimenti "si sovrapponga" a causa del tipo di dati utilizzato per contenere il conteggio dei riferimenti? O qualcos'altro? – helloworld922

+3

Immagina solo che A regge un ptr a B e B che punta a A. –

+0

Ah, capisco. Grazie.Troppo scarso overflow dello stack non ti consente di contrassegnare più buone risposte :(Penso che entrambe siano ottime risposte – helloworld922

0

In un semplice sistema di raccolta dei dati inutili, nessuno terrà un puntatore diretto a qualsiasi oggetto; invece, il codice manterrà i riferimenti alle voci della tabella che puntano agli oggetti sull'heap. Ogni oggetto sull'heap memorizzerà le sue dimensioni (ovvero tutti gli oggetti heap formeranno un elenco collegato singolarmente) e un riferimento all'oggetto nella tabella degli oggetti che lo contiene (o almeno lo usa).

Quando l'heap o la tabella degli oggetti si riempie, il sistema imposta un flag "delete me" su ogni oggetto nella tabella. Esaminerà ogni oggetto di cui è a conoscenza e, se è stato impostato il suo "flag di cancellazione", lo disinserisce e aggiunge tutti gli oggetti che conosce alla lista di oggetti da esaminare. Fatto ciò, qualsiasi oggetto il cui flag "delete me" è ancora impostato può essere cancellato.

Una volta fatto, il sistema inizierà all'inizio dell'heap, prenderà ogni oggetto lì memorizzato e vedrà se il suo riferimento all'oggetto continua a puntare su di esso. In tal caso, copierà quell'oggetto all'inizio dell'heap o appena oltre la fine dell'ultimo oggetto copiato; altrimenti l'oggetto verrà saltato (e verrà probabilmente sovrascritto quando altri oggetti vengono copiati).