Frage

Wir haben ein paar Operationen, bei denen wir eine große Anzahl von großen String Verkettungen tun, und haben vor kurzem einen der Speicher Ausnahme aufgetreten. Leider ist der Debugging-Code ist keine Option, da dies vor Ort beim Kunden auftritt.

Also, bevor sie in eine Überarbeitung unserer Code suchen, würde ich fragen: Was ist die RAM-Verbrauchseigenschaften von String für große Strings?

Vor allem, da sie auf den Standard-String-Typen vergleichen. Die Größe der Saiten sind deutlich mehr als 10 MB, und wir scheinen in den Fragen rund 20 MB ausgeführt werden.

Hinweis : Es geht nicht um Geschwindigkeit, sondern RAM

.
War es hilfreich?

Lösung

Hier ist eine schöne Studie über String Concatenation vs Speicherzuordnung .

  

Wenn Sie vermeiden können, verketten, tun Sie es!

     

Dies ist ein Klacks, wenn Sie nicht tun   müssen verketten wollen aber Ihre   Quellcode zu schön aussehen, verwenden Sie die   erstes Verfahren. Es wird noch optimiert,   wenn es eine einzelne Zeichenfolge.

     

+ nicht = Verkettungs verwendet je. Zu vielen Veränderungen statt   hinter den Kulissen, die nicht offensichtlich sind   von meinem Code an erster Stelle. ich   raten eher zu verwenden String.Concat ()   explizit bei jeder Überlastung (2   strings, 3 Strings, String-Array).   Dies wird deutlich zeigen, was Ihr Code   tut ohne Überraschungen, während   so dass Sie sich selbst einen Zaum halten auf   das Wirkungsgrad.

     

Versuchen Sie, die Zielgröße eines String zu schätzen.

     

Je genauer Sie können die Schätzung   benötigte Größe, desto weniger temporäre   Strings die String müssen   schaffen ihre internen zu erhöhen   Puffer.

     

Verwenden Sie kein Format () verwenden Methoden, wenn die Leistung ist ein Problem.

     

Zu viel Aufwand beteiligt ist   Parsen das Format, wenn Sie könnten   ein Array aus Stücken konstruieren, wenn   alles, was Sie verwenden, sind {x} ersetzt.   Format () ist gut für die Lesbarkeit, aber   eines der Dinge, zu gehen, wenn Sie sind   Quetschen alle möglichen Leistung aus   Ihre Anwendung.

Andere Tipps

Jedes Mal, String der Platz ausgeht, ordnet es ein neuer Puffer zweimal die Größe des ursprünglichen Puffer, kopiert die alten Zeichen und lässt die alte Puffer GC'd bekommen. Es ist möglich, dass Sie gerade genug, um unter Verwendung von (nennen wir es x), so dass 2x größer als der Speicher ist Sie zuordnen erlaubt sind. Möglicherweise möchten Sie eine maximale Länge für die Saiten, um zu bestimmen, und es an den Konstruktor Stringgeben, so dass Sie preallocate, und du bist nicht auf Gedeih und Verderb der Verdoppelung Umverteilung.

Sie könnten durch die Seile Datenstruktur interessiert. Dieser Artikel: Seile: Theorie und Praxis erklärt ihre Vorteile. Vielleicht gibt es eine Implementierung für .NET.

[Update, um den Kommentar zu beantworten] Ist es weniger Speicher? Suchen Speicher in dem Artikel finden Sie einige Hinweise finden.
Grundsätzlich ja, trotz der Struktur Overhead, weil es kommt noch hinzu, Speicher, wenn nötig. Stringbuilder, wenn alte Puffer anstrengend, muss eine viel größere zuweisen (die bereits leere Speicher verschwenden) und fällt die alten (der Müll gesammelt wird, kann aber noch vielen Speicher in der Zwischenzeit verwenden).

Ich habe nicht eine Implementierung für .NET, aber es ist zumindest eine C ++ Implementierung (in SGIs STL gefunden rel = "nofollow noreferrer"> http://www.sgi.com/tech/stl/Rope.html ). Vielleicht können Sie diese Implementierung nutzen. Beachten Sie die Seite Ich habe verweisen auf eine Arbeit auf die Gedächtnisleistung.

Beachten Sie, dass Seile nicht die Heilung für alle Probleme sind: ihre Nützlichkeit stark davon abhängt, wie Sie Ihre große Strings zu bauen, und wie man sie benutzt. Die Artikel weisen darauf hin, Vor- und Nachteile.

Strigbuilder ist eine ganz gute Lösung für Speicherprobleme, die durch Verketten von Strings.

Ihre Frage zu beantworten, hat eine konstante Stringgroßen Aufwand im Vergleich zu einem normalen String, wo die Länge der Zeichenfolge der Länge des aktuell zugewiesenen Stringpuffer gleich ist. Der Puffer könnte möglicherweise doppelt so hoch sein die Größe der Zeichenfolge, die sich ergibt, aber nicht mehr Speicherzuordnungen erfolgt, wenn auf den String verketten, bis der Puffer gefüllt ist, so ist es wirklich eine ausgezeichnete Lösung.

mit String-Vergleich, das ist hervorragend.

string output = "Test";
output += ", printed on " + datePrinted.ToString();
output += ", verified by " + verificationName;
output += ", number lines: " + numberLines.ToString();

Dieser Code hat vier Saiten, die als Literale im Code gespeichert, zwei, die in den Verfahren und einem aus einer Variablen erstellt werden, aber es nutzt sechs separate Zwischenketten, die länger und länger. Wenn dieses Muster fortgesetzt wird, wird es die Speicherauslastung mit einer exponentiellen Rate zu erhöhen, bis der GC in kickt ihn aufzuräumen.

Ich weiß nicht, über die genau Speichermuster von String-Builder, aber die gemeinsamen Zeichenfolge ist keine Option.

Wenn Sie die gemeinsame Zeichenfolge verwenden jede Verkettung noch ein paar String-Objekte erzeugt, und den Speicherverbrauch skyrocket, so dass der Garbage Collector zu oft aufgerufen wird.

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top