2009-11-06 8 views
11

Ich versuche, einen einfachen Resource Manager für das kleine Hobby-Spiel zu schreiben, das ich schreibe. Eine der Aufgaben, die dieser Ressourcenmanager ausführen muss, ist das Löschen nicht verwendeter Ressourcen. Ich kann auf zwei Arten denken, dies zu tun:C# - Anzahl der Referenzen auf Objekt

  • Wenn ein Objekt nicht mehr Referenz auf die Ressource erfordert, muss es ein Verfahren der Resource Manager nennen es zu bedeuten, nicht mehr mit ihm; oder

  • Wenn ein Objekt nicht mehr benötigt Bezugnahme auf die Ressource, es ist einfach setzt es auf den Wert null. Wenn dann der Ressourcenmanager aufgefordert wird, unbenutzte Ressourcen zu entladen, erhält er die Referenzzahl (über die Reflektion?) Von jeder Ressource. Wenn der Referenzzähler eins ist (der Ressourcenmanager hat einen Verweis auf die Ressource), entladen Sie die Ressource.

Gibt es eine Möglichkeit, die zweite Lösung in C# zu erreichen? Danke.

+0

Was wird Ihr Ressourcenmanager tun, was der Garbace Collector nicht tut? – CannibalSmith

+1

@CannibalSmith - in der Regel erlauben mehrere Bits Code, die Ressource (im Wesentlichen ein Cache) wiederzuverwenden –

+0

Sein zum Laden von Bildern, so dass immer nur ein Bild geladen wird (egal wie viele Dinge nur danach fragen eine Version kann im Speicher sein). –

Antwort

11

Es klingt für mich, dass Sie einfach WeakReference aus dem Ressourcen-Manager verwenden können. Der GC wird den Rest erledigen. Sie müssen ein wenig Casting machen, aber es wird einfach sein und wird funktionieren.

class Manager { 
    Dictionary<string, WeakReference> refs = 
     new Dictionary<string, WeakReference>(); 
    public object this[string key] { 
     get { 
      WeakReference wr; 
      if (refs.TryGetValue(key, out wr)) { 
       if(wr.IsAlive) return wr.Target; 
       refs.Remove(key); 
      } 
      return null; 
     } 
     set { 
      refs[key] = new WeakReference(value); 
     } 
    } 
} 
static void Main() { 
    Manager mgr = new Manager(); 
    var obj = new byte[1024]; 
    mgr["abc"] = obj; 

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
    Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj") 

    obj = null; 
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
    Console.WriteLine(mgr["abc"] != null); // false (no remaining refs) 
} 
+0

Ich würde dies tun :) Eine Sache, obwohl: Ich könnte falsch liegen, aber ich denke, Sie müssen möglicherweise die richtige Referenz aus dem Wörterbuch und überprüfen, ob es null ist, bevor Sie es zurückgeben. Wenn Sie "if (wr.IsAlive) wr.Target zurückgeben", nehmen Sie nie einen starken Verweis, sodass IsAlive möglicherweise true zurückgibt, aber bis Sie den Wert zurückgegeben haben, wurde möglicherweise wr.Target gesammelt. Hier gibt es ein alternatives Codebeispiel: http://msdn.microsoft.com/en-us/library/system.weakreference.aspx –

+1

'object' ist stark genug, um eine Sammlung zu verhindern; entweder wird es "null" oder stark sein. Der Aufrufer müsste es umwandeln, um es zu einer * typisierten * Referenz zu machen, aber das ist ein anderes Problem ... –

+0

.NET 4.5 hat eine generische Version von WeakReference, überprüfen Sie diese http://www.philosophicalgeek.com/2014/08/14/prefer-weakreference-to-weakreference / – Logerfo

2

Wir haben bereits einen Ressourcenmanager in .NET, den sogenannten Garbage Collector. Ein sehr effizienter Ansatz besteht also darin, die Referenzen auf null zu setzen und nichts zu tun.

Eine direktere Antwort: Nein, es gibt keine Möglichkeit, die Referenzen zu ein Objekt zu erhalten.

Sie können die WeakReference class studieren oder ein Caching-System verwenden.

1

Stellen Sie sicher, dass der Ressourcenmanager WeakReference s für Ihre Ressourcen verwendet. Auf diese Weise, wenn kein anderer auf die Ressourcen verweist, sind sie für die Garbage Collection geeignet.

0

Wie bereits von anderen Nutzern gesagt, was Sie versuchen zu erreichen, bereits durch die GC gemacht wird, und kann fein mit einem WeakReference abgestimmt werden.

Dies bedeutet, dass dies in verwalteten Umgebungen wie .NET, Java usw. kein Problem ist.

Da die Low-Level-Framework-Architektur Sie von der Speicherverwaltung isoliert, wenn Sie noch für diese Art von Funktionalität benötigen, empfehle ich Ihnen dringend, Ihre eigene Code-Architektur zu überprüfen, weil es bedeuten würde, dass Sie irgendeine Art von tun schlechte Praxis in der Speicherverwaltung

28

Paar Dinge. Zunächst einmal werden Objekte nicht als Referenz gezählt. Referenzzählungsschemata haben das Zirkelbezugsproblem, wobei sich zwei Objekte aufeinander beziehen, ansonsten aber unzugänglich sind und dadurch undicht werden. .NET verwendet einen Mark-and-Sweep-Ansatz, der Refcounts nicht verwendet.

Zweitens, obwohl der Vorschlag, eine schwache Referenz zu verwenden, ist nicht schrecklich, es ist auch kein Slam Dunk. Sie erstellen aus Leistungsgründen einen Cache.(Ich nehme an, dass Ihre sorgfältige, empirische, realistische Untersuchung der Leistungsmerkmale Ihrer Anwendung überzeugend gezeigt hat, dass eine Caching-Strategie notwendig ist, um eine akzeptable Leistung zu erzielen; wenn dies nicht der Fall ist, treffen Sie diese Entscheidungen vorzeitig.) Jeder Cache muss eine POLICY haben, wenn es seine Ressourcen freigibt, sonst ist es ein Speicherleck.

Woher wissen Sie, dass die GC-Richtlinie und Ihre Richtlinie gleichwertige Richtlinien sind? Der GC wurde nicht mit Ihren spezifischen Leistungsanforderungen entworfen. Das heißt, es wurde entwickelt, Ressourcen freizugeben, die wirklich Müll sind, und nicht, um ein bestimmtes Leistungsziel zu erreichen, das Sie im Sinn haben. Indem Sie die Entscheidung an den GC delegieren, geben Sie Ihre Fähigkeit auf, Ihre Cache-Richtlinie an Ihre Leistungsanforderungen anzupassen.

Verwandte Themen