Was ist String RAM Verbrauch wie?
-
02-07-2019 - |
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
.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).
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