Gibt es eine gängige Praxis, wie für Garbage Collector einfacher in .NET zu befreien Speicher zu machen?

StackOverflow https://stackoverflow.com/questions/2714811

Frage

Ich habe nachgedacht, ob es einen Weg gibt, wie das Gedächtnis beschleunigen Freisetzung in .NET. Ich bin ein Spiel in .NET (nur verwalteten Code) zu schaffen, wo keine signifikanten Grafiken benötigt werden, aber immer noch würde Ich mag es, um nichts zu nicht zu verlieren Leistung richtig schreiben.

Zum Beispiel ist es sinnvoll, assign Nullwert auf Objekte, die nicht mehr benötigt werden? Ich sehe dies in einigen Proben über das Internet.

War es hilfreich?

Lösung

ist es sinnvoll, assign Nullwert auf Objekte, die nicht mehr benötigt werden?

Im Allgemeinen nicht. Die meisten Proben werden Sie online sehen, die dies tun sind von Menschen, die auf .Net von VB6 kam, wo dies eine gemeinsame Best-Practice war. In .Net, ist es weniger hilfreich. Wenn Sie eine sehr lange Lauf Methode haben, kann es der Garbage Collector lassen das Objekt ein wenig früher finden - aber wenn Ihre Methode so lange ist Sie haben andere Probleme.

Stattdessen in .Net sollten Sie kurze Methoden bauen und Ihre Variablen so spät wie möglich in den kleinsten Umfang Blöcke möglich definieren. Verwenden Sie die „natürliche“ Lebenszeit der Variablen wie Umfang bestimmt, aber halten, dass natürliche Lebensdauer kurz.

Sie sollten nicht Ihre eigene Garbage Collection tun, wie hier durch mindestens eine andere Antwort vorgeschlagen. Dies kann tatsächlich Dinge machen langsamer . NET verwendet einen Generations-Speicherbereinigungs. Durch Erzwingen einer Garbage Collection, Sie können sammeln das Zielobjekt (man könnte auch nicht - es gibt keine Garantien mit Garbage Collection). Aber Sie werden wahrscheinlich auch dazu zwingen, eine Reihe von anderen Objekten, dass man nicht collect noch in einer höheren Ordnung Generation gespeichert werden, um sie härter machen in der Zukunft zu sammeln. Also einfach tun dies nicht.

Andere Tipps

Sie sollten nicht zu viele Sorgen und nicht optimize vorzeitig. Speicherverwaltung in .NET ist automatisch und sehr effizient. Wenn Sie auf ‚Optimieren‘ soll man anfangen müssen Sie genau wissen, was Sie tun, oder Sie können es verlangsamen.

beenden So Ihr Spiel zuerst, und dann, wenn es zu langsam ist einen Profiler, um das Problem zu finden. Höchstwahrscheinlich wird es kein Speicherproblem sein.

Die meisten der Grafikobjekte in .net Zusammenhang (Bild und seine Nachkommen, Grafik, Stift, Pinsel, etc.) implementieren IDisposable. Wenn Sie vorhaben, ein Objekt für einen bestimmten Vorgang zu verwenden, dann nicht wieder, verwenden Sie das folgende Muster:

using(var g = Graphics.FromBitmap(bmp))
{
    //Do some stuff with the graphics object
}

es so Dadurch wird sichergestellt alle nicht verwalteten Ressourcen frei bekommen, wenn sie von Rahmen fallen aus.

Ich finde Objekte in .net eines der Dinge, die Zuteilung, die Leistung wirkt sich auf die meisten. Um dies zu umgehen Ich benutze das ein Fabrikmuster, in dem ich Objekte recyceln, dass ich verwendet habe. Hier ist einfach generische Implementierung:

internal class ListFactory<T> 
    where T: IRecyclable, new()
{
    private List<T> _internalList;
    private int _pointer;

    public ListFactory()
    {
        _internalList = new List<T>();
        _pointer = 0;
    }

    public void Clear()
    {
            _pointer = 0;
    }

    public int Count
    {
        get
        {
            return _pointer;
        }
    }

    public List<T> InnerList
    {
        get
        {
            return _internalList;
        }
    }

    //Either return T form the list or add a new one
    //Clear T when it is being reused
    public T Create()
    {
        T t;

        //If the pointer is less than the object count then return a recycled object
        //Else return a new object 
        if (_pointer < _internalList.Count )
        {
            t = _internalList[_pointer];
            t.Recycle();
        }
        else
        {
            t = new T();
            _internalList.Add(t);
        }
        _pointer ++;
        return t;
    }
}

Für meine Linie Routing-Algorithmus, ich brauche viele Werte ständig zu halten, wie ein RouteNode , welche Geräte die folgende Schnittstelle:

public interface IRecyclable
{
    void Recycle();
}

Gelangen Sie ständig erstellt und zerstört. Um diese Aufgaben zu recyceln, erstellen Sie eine neue Fabrik:

nodeFactory = new ListFactory<RouteNode>();

Wenn Sie ein Objekt benötigen, rufen Sie die create-Methode:

RouteNode start = nodeFactory.Create();
RouteNode goal = nodeFactory.Create();

Wenn Sie mit den Objekten in der Liste abgeschlossen haben, deaktivieren Sie die Liste. Der Zeiger ist auf den Anfang der Liste zurückgesetzt, aber die Objekte selbst nicht zerstört werden. In der Tat wird die Recycle-Methode nur dann aufgerufen, wenn das Objekt wieder freigegeben wird. (Sie können diese früher tun, wenn Sie andere Objektreferenzen haben, siehe Kommentare unten)

Dies ist eine ziemlich naive Implementierung, aber es ist ein Anfang.

Es kann in einigen Fällen zu Satz Objekte auf null, die nicht mehr benötigt werden nützlich sein. Oft ist es nutzlos oder kontraproduktiv, aber nicht immer. Vier Haupt-Situationen, in denen es hilfreich sein kann:

  • Objekte enthält Felder deklariert als „Withevents“ in vb.net sollte IDisposable implementieren, und sollten diese Felder in der Dispose-Methode auf Null gesetzt. Ich weiß nicht, warum vb.net nicht eine schöne Art und Weise automatisch nulling Withevents Felder umfassen, aber da es nicht der Fall ist müssen sie manuell gelöscht werden.
  • Wenn eine lokale Variable enthält einen Verweis auf ein Objekt, das in der Tat nie wieder verwendet werden, aber es kann eine Weile dauern, bis der Code einen Punkt erreicht, wo der Compiler die Variable weiß nicht gewöhnen, Clearing- die Variable kann ermöglichen die Referenz früher freigegeben werden.
  • Wenn irgendwann ein Array, das groß ist, oder gibt es schon seit einiger Zeit bekannt ist, nutzlos zu sein, und wenn Hinweise auf einige kürzlich zugewiesenen Objekte gespeichert sind darin, diese Verweise Clearing bevor alle überlebenden zerstören Verweise auf das Array können die neu erstellte Objekte viel früher befreit werden lassen, als sie es sonst der Fall wäre.
  • Wenn ein Objekt eine Finalisierung Routine und ist in den Finalisierungsschlange alle Objekte direkt oder indirekt von ihr verwiesen werden von der Garbage Collection befreit werden. Folglich sollten finalizable Objekte nicht etwas verweisen, das nicht für die Fertigstellung benötigt werden.

  • Um dies zu tun (und ich habe dies zu tun habe, mit häufigen> 50mb Zuweisungen), Aufruf:

            myObj = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
    

    Ich habe bemerkt, dass der Speicherbedarf der App wird dann erheblich verringern. Theoretisch sollten Sie dies nicht tun müssen, um. Doch in der Praxis mit einem 32-Bit-Windows-Betriebssystem können Sie zwei zusammenhängende Blöcke von bekommen> 300mb frei zu einem bestimmten Zeitpunkt, und dass der Raum mit durch viele kleine Zuteilungen oder eine Reihe von Großes können, dass andere große Zuweisungen bedeuten aufgenommen werden nicht unnötig. Der Garbage Collector läuft im Hintergrund, wenn sie kann, aber wenn Sie absolut große Zuteilungen jetzt machen müssen, dass Satz von Linien hilft mir das möglich zu machen.

    EDIT:. Von dem, was ich in den Kommentaren stellen, für die downvoters

    Wenn Sie lesen die gesamte Post über die Garbage Collection von Rico Mariani , werden Sie feststellen, dass große, selten beachten, nicht vorhersagbaren Speicherzuordnungen fallen in Szenario # 2. Um Whit:

    Regel # 2

    Betrachten GC.Collect () aufgerufen wird, wenn einige Nicht-wiederkehrendes Ereignis hat gerade passiert und dieses Ereignis ist sehr wahrscheinlich haben viele alte Objekte verursacht sterben.

    Ein klassisches Beispiel dafür ist, wenn Sie Schreiben einer Client-Anwendung und Sie zeigen eine sehr große und kompliziert Form, die eine Menge von Daten zugeordnet ist damit. Ihr Benutzer hat nur interagierten potenziell mit diesem Formular Erstellen einige große Objekte ... Dinge wie XML-Dokumente oder ein großer DataSet oder zwei. Wenn das Formular schließt diese Objekte sind tot und so GC.Collect () wird zurückfordern den Speicher zugeordnet mit ihnen.

    Nun, warum würde ich vorschlagen, dies als ein wie möglich den Kollektor zu nennen? Ich meine, meine übliche Beratung geht etwas wie „ist der Kollektor Selbstoptimierung so verwirren nicht mit ihm.“Warum die Änderung Haltung könnte man fragen?

    Nun, hier ist eine Situation, in der Sammler tendancy [sic], um zu versuchen, vorherzusagen, die Zukunft auf der Grundlage der Vergangenheit wahrscheinlich als nicht erfolgreich.

    Wenn Sie große Zuweisungen in Ihrem Spiel zu machen, müssen Sie vorsichtig sein, wie das Gedächtnis behandelt wird. Der Garbage Collector arbeitet auf der Vorhersage auf vergangenen Ereignissen beruhen und große Speicherblöcke auf einem 32-Bit-Maschine kann auf künftige Zuteilungen verheerend sein, wenn nicht richtig verwaltet. Wenn Sie es nicht getan haben, nicht automatisch davon ausgehen, dass ich falsch liege; wenn Sie es getan haben, würde ich eine Erklärung begrüßen, wie es richtig zu machen (das heißt, wie man Defrag.speicher, um sicherzustellen, kann ich immer Zuordnung 50-100mb Speicher zu einem bestimmten Zeitpunkt).

    Lizenziert unter: CC-BY-SA mit Zuschreibung
    Nicht verbunden mit StackOverflow
    scroll top