Domanda

  

Il distruttore dovrebbe rilasciare solo risorse non gestite su cui si trova l'oggetto e non deve fare riferimento ad altri oggetti. Se hai gestito solo riferimenti non devi (e non dovresti) implementare un distruttore. Lo vuoi solo per la gestione di risorse non gestite. Poiché ci sono dei costi per avere un distruttore , dovresti implementarlo solo su metodi che consumano risorse preziose e non gestite.

     

- Le dieci migliori trappole in C # per C ++ I programmatori

L'articolo non approfondisce questo aspetto, ma quali sono i costi associati all'utilizzo di un distruttore in C #?

Nota: so del GC e del fatto che il distruttore non viene chiamato in momenti affidabili, che a parte tutto, c'è qualcos'altro?

È stato utile?

Soluzione

Qualsiasi oggetto che ha un finalizzatore (preferisco quel termine al distruttore, per enfatizzare la differenza dai distruttori C ++) viene aggiunto alla coda del finalizzatore. Questo è un elenco di riferimenti a oggetti che hanno un finalizzatore che deve essere chiamato prima che vengano rimossi.

Quando l'oggetto è pronto per la garbage collection, il GC troverà che si trova nella coda del finalizzatore e sposta il riferimento nella coda freachable (f-raggiungibile). Questo è l'elenco che il thread in background del finalizzatore attraversa per chiamare a turno il metodo finalizzatore di ciascun oggetto.

Una volta chiamato il finalizzatore dell'oggetto, l'oggetto non è più nella coda del finalizzatore, quindi è solo un normale oggetto gestito che il GC può rimuovere.

Tutto ciò significa che se un oggetto ha un finalizzatore, sopravviverà almeno una garbage collection prima che possa essere rimosso. Questo di solito significa che l'oggetto verrà spostato alla generazione di heap successiva, il che comporta effettivamente lo spostamento dei dati in memoria da un heap a un altro.

Altri suggerimenti

La discussione più ampia che ho visto come tutto questo è stato fatto da Joe Duffy . Ha più dettagli di quanto tu possa immaginare.

In seguito, ho messo insieme un approccio pratico per farlo quotidianamente, meno per quanto riguarda i costi ma più per l'attuazione.

Guffa e JaredPar coprono abbastanza bene i dettagli, quindi aggiungerò semplicemente una nota un po 'esoterica su finalizzatori o distruttori, come purtroppo li chiama la specifica del linguaggio C #.

Una cosa da tenere a mente è che, poiché il thread del finalizzatore esegue tutti i finalizzatori in sequenza, un deadlock in un finalizzatore impedirà l'esecuzione di tutti i finalizzatori rimanenti (e futuri). Poiché queste istanze non vengono raccolte fino a quando i loro finalizzatori non completano un finalizzatore bloccato, si verificherà anche una perdita di memoria.

Questo articolo tratta il problema in dettaglio. È davvero difficile riassumere in un semplice post SO: http: // msdn. microsoft.com/en-us/magazine/bb985010.aspx

Guffa ha riassunto abbastanza bene i fattori del costo del finalizzatore. C'è stato un recente articolo sul costo dei finalizzatori in Java che fornisce anche alcune informazioni.

Parte del costo in .net può essere evitato rimuovendo l'oggetto dalla coda del finalizzatore con GC.SuppressFinalize. Ho eseguito alcuni test rapidi in .net in base all'articolo e l'ho pubblicato qui (sebbene il focus sia molto più sul lato Java).


Di seguito è riportato un grafico dei risultati: in realtà non ha le migliori etichette ;-). & Quot; debug = true / false " si riferisce al finalizzatore vuoto vs semplice:

~ConditionalFinalizer()  
{  
    if (DEBUG)  
    {  
        if (!resourceClosed)  
        {  
            Console.Error.WriteLine("Object not disposed");  
        }  
        resourceClosed = true;  
    }  
} 

" Soppressione = true " indica se GC.SuppressFinalize è stato chiamato nel metodo Dipose.

Sommario

Per .net, rimuovere l'oggetto dalla coda del finalizzatore chiamando GC.SuppressFinalize è la metà del costo di lasciare l'oggetto nella coda.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top