2 Stimmen

Schnelle Wiederherstellung des Stringspeichers (Gerät mit begrenztem RAM)

Ich schreibe eine C#-Anwendung für ein Gerät mit begrenztem Speicherplatz (Mono auf iPhone/iPad).

Wenn ich eine große Zeichenfolge zuweise:

string xml = "10 meg xml string from REST service";

dann löschen Sie es

xml = null;

Ist mit der GC freigeben, dass der Speicher so schnell wie möglich? Gibt es einen Weg, um sicherzustellen, dass er aufgeräumt wird. GC hat eine Sammelfunktion, aber wird diese sofort ausgeführt?

Das Problem ist, dass ich viele große XML-Dateien in einer Schleife herunterlade, und obwohl ich die Zeichenfolge auf null setze, steigt der Speicherverbrauch.

4voto

Donnie Punkte 43338

Im Allgemeinen wird GC nicht sofort durchgeführt, da die Garbage Collection relativ teuer ist. Die Laufzeitumgebung versucht im Allgemeinen, dies zu tun, während sie nicht mit anderen Dingen beschäftigt ist, aber das ist natürlich nicht immer möglich. Ich bin einmal in einen nicht-deterministischen Out-of-Memory-Fehler geraten, weil die GC zu lange aufgeschoben wurde (manchmal), während ich eine speicherintensive Schleife ausführte. Lektion: Im Allgemeinen weiß der Collector, was er tut, und man braucht ihn nicht zu optimieren. Aber nicht immer.

Um eine Einziehung zu erzwingen, benötigen Sie zwei Zeilen:

GC.Collect();
GC.WaitForPendingFinalizers();

EDIT: Ich habe das geschrieben, bevor ich Ihren Hinweis auf das, was Sie verwenden, gesehen habe. Dies ist auf der Grundlage der Desktop-.NET-Maschine geschrieben. Es kann (oder auch nicht) anders auf mono / iPad sein.

2voto

lupus Punkte 3943

Erstens sollte es vermieden werden, große Zeichenketten oder große Arrays gleichzeitig im Speicher zu halten, insbesondere auf Geräten mit begrenztem Speicherplatz wie Telefonen. Verwenden Sie zum Beispiel XmlTextReader, um Xml-Dateien zu parsen. Wenn Sie sie aus dem Netzwerk beziehen, speichern Sie sie auf der Festplatte, usw.

Als nächstes das Problem der Garbage Collection: Die aktuelle Mono GC führt einen konservativen Scan der Thread-Stacks durch, was bedeutet, dass einige Zeiger auf Objekte für die GC immer noch sichtbar sein können, auch wenn sie für den Programmierer gelöscht wurden (wie das Setzen auf null in Ihrem Beispiel). Um die Folgen dieses Verhaltens zu begrenzen, sollten Sie versuchen, große Arrays und Strings in einem separaten Stack-Frame zu allozieren oder anderweitig zu manipulieren. Zum Beispiel, anstatt es so zu kodieren:

  while (true) {
    string s = get_big_string_from_network ();
    do_something_with_string(s);
    handle_ui ();
    s = null;
  }

tun Sie Folgendes:

  void manipulate_big_string() {
    string s = get_big_string_from_network ();
    do_something_with_string(s);
  }
  ...
  while (true) {
    manipulate_big_string ();
    handle_ui ();
  }

Normalerweise hat das Setzen eines Verweises auf null nur dann die beabsichtigte Wirkung, wenn es auf ein statisches oder Instanzfeld angewendet wird. Die Verwendung mit einer lokalen Variablen einer Methode reicht möglicherweise nicht aus, um den Verweis vor der GC zu verbergen.

2voto

Juan Punkte 1302

Ich denke, wenn Sie für das iPhone entwickeln, haben Sie nicht den Garbage Collector aus dem .net Framework. Die Speicherverwaltung wird durch das Betriebssystem in diesem Fall das iOS gemacht.

Ich denke, Sie sollten in der Mono-Dokumentation nachsehen, wie Sie den Speicher in diesem Fall verwalten können. XCode implementiert eine automatische Objektverwaltung, die automatische Referenzzählung genannt wird und ist keine Garbage Collection wie die im .net Framework, sondern nur ein automatisches Werkzeug, um unbenutzte Objekte freizugeben.

Gerade in .net, wenn man mit großen Strings arbeitet, sollte man immer stringbuilder statt nur string verwenden.

Wenn Sie jetzt an iOS denken, sollten Sie die für die iOS-Umgebung geschriebene Anwendung nicht mit einer Desktop-Anwendung für Windows vergleichen (auf einem PC haben Sie viel mehr Ressourcen). Das iOS erlaubt keinen großen Anstieg des Speicherverbrauchs. Wenn eine App dies tut, schließt das Betriebssystem sie automatisch, um das System am Laufen zu halten.

1voto

Bob Palmer Punkte 4666

Ich bin zwar kein Mono-Experte, aber einige einfache Dinge zu überprüfen. Sie haben zwar festgestellt, dass Sie Ihre Variable auf null setzen, aber rufen Sie tatsächlich eine .Close()- oder .Dispose()-Methode auf, oder schließen Sie den Bereich der fraglichen Variable in einen using-Block ein?

Könnte ein Fall von einem Problem sein, wo Sie bleiben, um für einen Finalizer warten (d.h. wenn Sie ein Handle auf eine unmalaged Ressource wie ein Dateihandle haben), oder die Variable ist immer noch im Bereich aus irgendeinem Grund stecken. Dies würde zu einem erhöhten Speicherbedarf führen.

Idealerweise öffnen Sie Ihre Datei einzeln in einer Methode mit explizit klarem Variablenbereich in Kombination mit einem using-Block, um sicherzustellen, dass die entsprechenden Finalizer usw. auch dann aufgerufen werden, wenn eine Ausnahme ausgelöst wird.

Ich hoffe, das hilft!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X