C# Language
Garbage Collector in .Net
Ricerca…
Compattazione del mucchio di oggetti di grandi dimensioni
Di default il Large Object Heap non è compattato a differenza del classico Object Heap che può portare alla frammentazione della memoria e, inoltre, può portare a OutOfMemoryException
s
A partire da .NET 4.5.1 esiste un'opzione per comprimere esplicitamente l'heap di oggetti di grandi dimensioni (insieme a una garbage collection):
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
Proprio come qualsiasi richiesta di garbage collection esplicita (si chiama richiesta perché CLR non è obbligato a condurla) usa con cautela e, per impostazione predefinita, evitala se puoi perché può GC
statistiche di GC
, diminuendo le sue prestazioni.
Riferimenti deboli
In .NET, il GC alloca gli oggetti quando non ci sono riferimenti a loro lasciati. Pertanto, mentre un oggetto può ancora essere raggiunto dal codice (c'è un forte riferimento ad esso), il GC non assegnerà questo oggetto. Questo può diventare un problema se ci sono molti oggetti di grandi dimensioni.
Un riferimento debole è un riferimento che consente al GC di raccogliere l'oggetto pur consentendo l'accesso all'oggetto. Un riferimento debole è valido solo durante l'intervallo di tempo indeterminato finché l'oggetto non viene raccolto quando non esistono riferimenti forti. Quando si utilizza un riferimento debole, l'applicazione può ancora ottenere un riferimento forte all'oggetto, che ne impedisce la raccolta. Quindi i riferimenti deboli possono essere utili per conservare oggetti di grandi dimensioni che sono costosi da inizializzare, ma dovrebbero essere disponibili per la raccolta dei dati inutili se non sono attivamente utilizzati.
Uso semplice:
WeakReference reference = new WeakReference(new object(), false);
GC.Collect();
object target = reference.Target;
if (target != null)
DoSomething(target);
Quindi riferimenti deboli potrebbero essere usati per mantenere, per esempio, una cache di oggetti. Tuttavia, è importante ricordare che c'è sempre il rischio che il garbage collector raggiunga l'oggetto prima che venga ristabilito un riferimento forte.
I riferimenti deboli sono anche utili per evitare perdite di memoria. Un tipico caso d'uso è con gli eventi.
Supponiamo di avere qualche gestore di un evento su una fonte:
Source.Event += new EventHandler(Handler)
Questo codice registra un gestore di eventi e crea un riferimento forte dall'origine evento all'oggetto in ascolto. Se l'oggetto di origine ha una durata maggiore rispetto al listener e il listener non ha più bisogno dell'evento quando non ci sono altri riferimenti ad esso, l'uso di eventi .NET normali causa una perdita di memoria: l'oggetto di origine contiene oggetti listener in memoria che dovrebbe essere raccolta dei rifiuti
In questo caso, potrebbe essere una buona idea usare il modello di evento debole .
Qualcosa di simile a:
public static class WeakEventManager
{
public static void SetHandler<S, TArgs>(
Action<EventHandler<TArgs>> add,
Action<EventHandler<TArgs>> remove,
S subscriber,
Action<S, TArgs> action)
where TArgs : EventArgs
where S : class
{
var subscrWeakRef = new WeakReference(subscriber);
EventHandler<TArgs> handler = null;
handler = (s, e) =>
{
var subscrStrongRef = subscrWeakRef.Target as S;
if (subscrStrongRef != null)
{
action(subscrStrongRef, e);
}
else
{
remove(handler);
handler = null;
}
};
add(handler);
}
}
e usato in questo modo:
EventSource s = new EventSource();
Subscriber subscriber = new Subscriber();
WeakEventManager.SetHandler<Subscriber, SomeEventArgs>(a => s.Event += a, r => s.Event -= r, subscriber, (s,e) => { s.HandleEvent(e); });
In questo caso ovviamente abbiamo alcune restrizioni: l'evento deve essere a
public event EventHandler<SomeEventArgs> Event;
Come suggerisce MSDN :
- Usa riferimenti deboli lunghi solo quando è necessario poiché lo stato dell'oggetto è imprevedibile dopo la finalizzazione.
- Evita di usare riferimenti deboli a oggetti piccoli perché il puntatore stesso potrebbe essere grande o più grande.
- Evitare l'uso di riferimenti deboli come soluzione automatica ai problemi di gestione della memoria. Invece, sviluppare una politica di caching efficace per la gestione degli oggetti dell'applicazione.