Garbage Collector in .Net

 C Programming >> C-Programmierung >  >> Tags >> .NET
Garbage Collector in .Net

# Schwache Referenzen

In .NET weist der GC Objekte zu, wenn keine Verweise mehr auf sie vorhanden sind. Obwohl ein Objekt noch vom Code aus erreicht werden kann (es gibt einen starken Verweis darauf), wird der GC dieses Objekt daher nicht zuweisen. Dies kann bei vielen großen Objekten zu einem Problem werden.

Eine schwache Referenz ist eine Referenz, die es dem GC ermöglicht, das Objekt zu sammeln, während es immer noch erlaubt, auf das Objekt zuzugreifen. Eine schwache Referenz ist nur während der unbestimmten Zeitspanne gültig, bis das Objekt gesammelt wird, wenn keine starken Referenzen vorhanden sind. Wenn Sie einen schwachen Verweis verwenden, kann die Anwendung dennoch einen starken Verweis auf das Objekt erhalten, wodurch verhindert wird, dass es erfasst wird. Schwache Referenzen können also nützlich sein, um große Objekte zu behalten, deren Initialisierung teuer ist, die aber für die Garbage Collection verfügbar sein sollten, wenn sie nicht aktiv verwendet werden.

Einfache Verwendung:

WeakReference reference = new WeakReference(new object(), false);

GC.Collect();

object target = reference.Target;
if (target != null)
  DoSomething(target);

So könnten schwache Referenzen verwendet werden, um beispielsweise einen Cache von Objekten zu verwalten. Es ist jedoch wichtig, daran zu denken, dass immer das Risiko besteht, dass der Garbage Collector an das Objekt gelangt, bevor eine starke Referenz wiederhergestellt ist.

Schwache Referenzen sind auch praktisch, um Speicherlecks zu vermeiden. Ein typischer Anwendungsfall sind Ereignisse.

Angenommen, wir haben einen Handler für ein Ereignis in einer Quelle:

Source.Event += new EventHandler(Handler)

Dieser Code registriert einen Ereignishandler und erstellt einen starken Verweis von der Ereignisquelle auf das lauschende Objekt. Wenn das Quellobjekt eine längere Lebensdauer als der Listener hat und der Listener das Ereignis nicht mehr benötigt, wenn keine anderen Verweise darauf vorhanden sind, führt die Verwendung normaler .NET-Ereignisse zu einem Speicherleck:Das Quellobjekt hält Listener-Objekte im Speicher sollte der Garbage Collection unterzogen werden.

In diesem Fall kann es eine gute Idee sein, das schwache Ereignismuster zu verwenden .

Etwas wie:

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);
        }
    }

und wie folgt verwendet:


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 diesem Fall haben wir natürlich einige Einschränkungen - das Ereignis muss ein

sein
public event EventHandler<SomeEventArgs> Event;

Wie MSDN vorschlägt:

  • Verwenden Sie lange schwache Referenzen nur, wenn es notwendig ist, da der Zustand des Objekts nach der Fertigstellung unvorhersehbar ist.
  • Vermeiden Sie schwache Verweise auf kleine Objekte, da der Zeiger selbst genauso groß oder größer sein kann.
  • Vermeiden Sie die Verwendung schwacher Referenzen als automatische Lösung für Speicherverwaltungsprobleme. Entwickeln Sie stattdessen eine effektive Caching-Richtlinie für die Handhabung der Objekte Ihrer Anwendung.
  • # Large Object Heap-Komprimierung

    Standardmäßig ist der Large Object Heap im Gegensatz zum klassischen Object Heap nicht komprimiert, was zu einer Speicherfragmentierung und darüber hinaus zu OutOfMemoryException führen kann s

    Beginnend mit .NET 4.5.1 gibt es eine Option zum expliziten Komprimieren des Large Object Heap (zusammen mit einer Garbage Collection):

    GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
    GC.Collect();   
    
    

    Genauso wie jede explizite Garbage-Collection-Anforderung (sie heißt Anforderung, weil die CLR nicht gezwungen ist, sie auszuführen) verwenden Sie sie mit Vorsicht und vermeiden Sie sie standardmäßig, wenn Sie können, da sie GC dekalibrieren kann s-Statistiken, was seine Leistung verringert.


    No