2012-01-05 22 views
7

In un titolo "Forzare un Colection Garbage" dal libro "C# 2010 e .NET 4 Piattaforma" da Andrew Troelsen scritto:indesiderati Garbage Collection

"Anche in questo caso, l'intero scopo di .NET Garbage Collector è gestire la memoria per nostro conto Tuttavia, in alcune circostanze molto rare, potrebbe essere utile forzare una raccolta dati in modo programmatico utilizzando GC.Collect(). Specificamente:

• L'applicazione sta per entrare in blocco di codice che non vuoi venga interrotto da una possibile garbage collection. ... "

Ma basta! C'è un caso del genere quando Garbage Collection non è desiderabile? Non ho mai visto/letto qualcosa del genere (a causa della mia piccola esperienza di sviluppo, ovviamente). Se durante la pratica hai fatto qualcosa del genere, per favore condividi. Per me è un punto molto interessante.

Grazie!

+7

Si prega di prendere nota speciale di * "alcune circostanze molto rare" * e non cospargere GC.Collect() su tutto il codice. –

+0

Sarà fatto! :) – Arterius

risposta

5

Eseguo un sito Web relativo alle ricette e memorizzo un enorme grafo di ricette e il loro utilizzo degli ingredienti in memoria. A causa del modo in cui faccio ruotare queste informazioni per un accesso rapido, devo caricare diversi giga di dati in memoria quando l'applicazione viene caricata prima di poter organizzare i dati in un grafico molto ottimizzato. Creo una quantità enorme di piccoli oggetti sull'heap che, una volta creato il grafico, diventano irraggiungibili.

L'operazione viene eseguita quando l'applicazione Web viene caricata e probabilmente sono necessari 4-5 secondi. Dopo averlo fatto, chiamo lo GC.Collect(); perché preferirei rivendicare tutta la memoria ora piuttosto che bloccare potenzialmente tutti i thread durante una richiesta HTTP in arrivo mentre il garbage collector sta impazzendo ripulendo tutti questi oggetti di breve durata.Immagino anche che sia meglio ripulire ora dato che l'heap è probabilmente meno frammentato in questo momento, dal momento che la mia app non ha ancora fatto nulla fino ad ora. Ritardare ciò potrebbe causare la creazione di molti più oggetti e l'heap deve essere compresso di più quando GC viene eseguito automaticamente.

Oltre a ciò, nei miei 12 anni di programmazione .NET, non mi sono mai imbattuto in una situazione in cui volevo forzare l'esecuzione del garbage collector.

7

Sì, c'è assolutamente un caso in cui la garbage collection non è desiderabile: quando un utente è in attesa che qualcosa accada, e deve aspettare più a lungo perché il codice non può procedere fino al completamento della garbage collection.

Questo è il punto di Troelsen: se si dispone di un punto specifico in cui si conosce un GC non è problematico ed è probabile che sia in grado di raccogliere una notevole quantità di spazzatura allora può essere una buona idea per provocare quindi, per evitare che si inneschi in un momento meno opportuno.

+0

Sai che non è un problema, anche più raro degli scenari in cui potresti desiderare ... –

+0

@TonyHopkinson: È relativamente raro, ma non mai sentito. Più precisamente, potresti ben sapere che è * meno * problematico ora di quanto lo sarebbe presto. –

+0

C'è sempre una ragione per infrangere le regole, non sostenendo che non dovresti mai farlo, solo che prima di romperle, dovresti capirle, in modo da poterle rompere efficacemente. –

1

Sarebbe molto raro, ma GC può essere un processo moderatamente costoso, quindi se c'è una particolare sezione sensibile alla temporizzazione, non si vuole che quella sezione venga interrotta da GC.

3

Si consiglia di non chiamare esplicitamente Collect nel codice. Riesci a trovare le circostanze in cui è utile?

Altri ne hanno dettagliati alcuni, e non ci sono dubbi. La prima cosa da capire però è non farlo. È l'ultima risorsa, studia altre opzioni, scopri come funziona GC e guarda come influisce il tuo codice, segui le best practice per i tuoi progetti.

Chiamare il numero Collect nel punto sbagliato peggiorerà le prestazioni. Peggio ancora, affidarsi a questo rende il tuo codice molto fragile. Le rare condizioni richieste per effettuare una chiamata a Collect utili, o alla fine non dannose, possono essere completamente annullate con una semplice modifica al codice, che si tradurrà in OOM inattese, prestazioni scadenti e così via.

2

L'ho chiamato prima delle misurazioni delle prestazioni in modo che il GC non falsi i risultati.

Un'altra situazione sono test unità di test per perdite di memoria:

object doesItLeak = /*...*/; //The object you want to have tested 
WeakReference reference = new WeakRefrence(doesItLeak); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 

Assert.That(!reference.IsAlive); 

Oltre a quelli, non ho incontrato una situazione in cui sarebbe effettivamente utile.
Soprattutto nel codice di produzione, GC.Collect non dovrebbe mai essere trovato IMHO.

1

L'applicazione sta per inserire un blocco di codice che non si desidera interrompere con una possibile raccolta dati inutili. ...

Un argomento molto sospetto (che tuttavia viene utilizzato molto).

Windows non è un sistema operativo in tempo reale. Il codice (Thread/Processo) può sempre essere anticipato dallo scheduler del SO. Non hai un accesso garantito alla CPU.

Quindi si riduce a: in che modo il tempo per una corsa GC è paragonabile a una fascia oraria (~ 20 ms)?

Su di esso sono disponibili pochissimi dati, ho cercato alcune volte.

Dalla mia osservazione (molto informale), una raccolta gen-0 è < 40 ms, in genere molto meno. Un gen-2 completo può essere eseguito in ~ 100 ms, probabilmente di più.

Quindi il "rischio" di essere interrotto dal GC è dello stesso ordine di grandezza di quello scambiato per un altro processo. E tu non puoi controllare quest'ultimo.