Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
RAM-Verbrauch bei JSON-Serialisierung großer Objekte optimieren
fungi35
myCSharp.de - Member



Dabei seit:
Beiträge: 39

Themenstarter:

RAM-Verbrauch bei JSON-Serialisierung großer Objekte optimieren

beantworten | zitieren | melden

Hallo Leute,

ich muss ein sehr großes Objekt (mit vielen enthaltenen Listen und weiteren Objekten) serialisieren und im Programmverlauf wieder deserialisieren (dieser Vorgang wird oft ausgeführt). Momentan wird das Objekt in einen JSON-String (Newton) serialisiert. Es scheint so, bzw. ich habe beobachtet, dass das ganze auf Dauer sehr RAM-intensiv ist.

Ist es so, dass ständiges bilden großer Strings (nichts anderes macht die Serialisierung in diesem Fall ja) viel RAM verbraucht? Kann man die Serialisierung und Deserialisierung großer Objekte auch so gestalten, dass nicht viel RAM für das Serialisieren des Objekts (= bisherige String-Serialisierung) verbraucht wird?

Sorry, wenn ich mich zu kompliziert ausgedrückt habe ;)


Gruß fungi
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7538
Herkunft: Waidring

beantworten | zitieren | melden

Hallo fungi35,
Zitat
Ist es so, dass ständiges bilden großer Strings (nichts anderes macht die Serialisierung in diesem Fall ja) viel RAM verbraucht?
Ja das ist so. V.a. dann wenn der StringBuilder nicht zum Einsatz kommt.
Bei Strings wird bei jeder Verkettung, Trim, Insert, ... ein neues Objekt erstellt und da hat der GC dann jede Menge zu tun.

Ob und inwiefern Newtonsoft hier Möglichkeiten zum Eingriff in die Serialisierung geschaffen hat weiß ich nicht, aber das lässt sich nachlesen.

Sonst kannst du dir überlegen ob du nicht in andere Formate serialisiert, die besser für große Datenmengen geeignet sind.
Wenns rein .net ist, so kannst du auch binäre serialisieren.
Sonst schau dir Google Protobuf an.

Du kannst aber auch das sehr große Objekt in kleinere Teile zerlegen, diese separat serialisieren und bei Bedarf zum Großen und Ganzen zusammenbauen. Am besten per eigenen Builder der sich darum kümmert.

mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5963
Herkunft: Leipzig

beantworten | zitieren | melden

Hi fungi35,
Zitat von fungi35
ein sehr großes Objekt (mit vielen enthaltenen Listen und weiteren Objekten) serialisieren und im Programmverlauf wieder deserialisieren

Geht es dabei um Datenübertragung oder -speicherung oder um etwas anderes? Je nach Anwendungsfall sind verschiedene Strategien denkbar, um die Datenmenge bzw. den Speicherverbrauch zu reduzieren.
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
fungi35
myCSharp.de - Member



Dabei seit:
Beiträge: 39

Themenstarter:

beantworten | zitieren | melden

Über die Serialisierung wird im Prinzip eine Objekt-Transaktion implementiert.
Beim Starten der Bearbeitung wird das Objekt serialisiert, beim Abbrechen der Bearbeitung wird es wieder deserialisiert und somit in seinen alten Zustand versetzt. Das dauert auch teilweise einen Moment, was ich auch gerne verbessern würde weil es die Usability und den Arbeitsfluss stört.

Ich hatte auch schon darüber nachgedacht, das ganze per Stream direkt in eine Datei zu schreiben und mir so den Weg über den riesigen String im Speicher zu sparen. Da stellte sich mir aber die Frage, ob diese Vorgehensweise die Performance wegen des Festplattenzugriffs nicht verschlechtern würde...

Zitat von gfoidl
Sonst kannst du dir überlegen ob du nicht in andere Formate serialisiert, die besser für große Datenmengen geeignet sind.
Wenns rein .net ist, so kannst du auch binäre serialisieren.
Sonst schau dir Google Protobuf an.

Google Protobuf sieht sehr interessant aus. Meinst Du, das könnte für meinen oben beschriebenen Anwendungsfall eine gute Anwendung sein?

Welche Vorgehensweise macht generell Sinn, wenn man große Inhalte "zwischenlagern" möchte, ohne das die Anwendung irgendwann einen sehr hohen Speicherverbrauch hat?
private Nachricht | Beiträge des Benutzers
unconnected
myCSharp.de - Member

Avatar #avatar-3200.jpg


Dabei seit:
Beiträge: 862
Herkunft: Oerlinghausen/NRW

beantworten | zitieren | melden

Hast Du schon mal über eine Datenbank nachgedacht? Abhängig von der Form deiner Daten, kannst Du hier immer nur das laden und schreiben was Du gerade bearbeitest. Ist auch vielleicht besser falls jemand deine Anwendung nicht abbricht, sondern hart abschiesst bzw. Stromausfall etc.
private Nachricht | Beiträge des Benutzers
fungi35
myCSharp.de - Member



Dabei seit:
Beiträge: 39

Themenstarter:

beantworten | zitieren | melden

Das ganze auf Datenbank-Transaktionen umzustellen kommt erstmal nicht in Frage, weil der Aufwand dafür viel zu hoch wäre.
private Nachricht | Beiträge des Benutzers
T-Virus
myCSharp.de - Member



Dabei seit:
Beiträge: 1821
Herkunft: Nordhausen, Nörten-Hardenberg

beantworten | zitieren | melden

@fungi35
Das halte ich für eine sehr gewagte Aussage.
Wenn eine Umstellung zu Aufwändig ist, dann ist der Code Mist.
Habt ihr euch dann an Basis Prinzipieen wie das Drei Schichten Model gehalten?
Oder wurde hier Code wild in die UI zusammen gepackt?

Ich sehe hier auch keinen sinnvolleren Weg als über eine DB.
In eurem Fall wahrscheinlich eine Anwendungsdatenbank ala Sqlite.
Serialisierung sollte man eher zur Datenübertragung als zur Datenhaltung nutzen.
Gerade bei großen Objekten, die intern eine tiefere Hierachie haben, kommt man mit Serialisierung nicht weit.

T-Virus
Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
private Nachricht | Beiträge des Benutzers
fungi35
myCSharp.de - Member



Dabei seit:
Beiträge: 39

Themenstarter:

beantworten | zitieren | melden

Ja, das Programm ist im Drei-Schichten-Model umgesetzt. Der Datenbankzugriff ist komplett von der UI getrennt.


Es wäre trotzdem nicht so leicht, das ganze auf Datenbank-Transaktionen umzustellen:

- Ein Auftrag wird geladen
- Die Positionen werden geladen (es geht in diesem Thread um die Bearbeitung der Positionen)


Auf DB-Transaktionen umzustellen würde bedeuten, dass beim Starten der Bearbeitung einer Position eine Transaktion gestartet würde, alle Änderungen die an der Position gemacht werden direkt in die Datenbank übernommen werden müssten und die Transaktion anschließend mittels COMMIT oder ROLLBACK beendet werden würde.
Mal angenommen, der Benutzer verwirft seine Änderungen und die Transaktion wird zurückgenommen, dann müsste man auch die Daten der Position aus der Datenbank neu laden, was wiederum auch keinen Geschwindigkeitsvorteil bringen würde. Desweiteren würden wir die Fähigkeit verlieren, das alle Änderungen NICHT übernommen werden, wenn man den gesamten Vorgang (in dem die Positionen enthalten sind) abbricht.
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3062
Herkunft: Thüringen

beantworten | zitieren | melden

Wurde ja schon gesagt, dass die Zeichenketten Ursache des Speicherproblems sind, das du hast. Dann serialisierst/deserialisierst du halt in einen (File-)Stream.


//there....

MyClass sourceObject = GetLargeObject();

JsonSerializer serializer = new JsonSerializer();
//Converter je nach Gusto hinzufügen, serializer konfigurieren....

using (var sw = new StreamWriter(filePath))
using (var writer = new JsonTextWriter(sw))
    serializer.Serialize(writer, sourceObject);


//...and back again.

MyClass destinationObject;

using (StreamReader file = File.OpenText(filePath))
{
    JsonSerializer serializer = new JsonSerializer();
    destinationObject = (MyClass)serializer.Deserialize(file, typeof(MyClass));
}
LaTino

EDIT: geht auch mit einem MemoryStream, und ich würde fast behaupten, auch da kannst wesentlich größere Objekte behandeln als auf deine bisherige Weise. Muss also kein File sein.
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von LaTino am .
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
private Nachricht | Beiträge des Benutzers
fungi35
myCSharp.de - Member



Dabei seit:
Beiträge: 39

Themenstarter:

beantworten | zitieren | melden

Danke LaTino, das werde ich direkt ausprobieren :)
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7538
Herkunft: Waidring

beantworten | zitieren | melden

Hallo fungi35,

wenn du Serialisierung für transaktionales Verhalten verwenden willst, so nimm doch binäre Serialisierung (BinaryFormatter), dann umgehst du das komplette String-Problem.
Allgemeiner: Es gibt jede Menge Serialisieren, d.h. für deinen Anwendungsfalls musst du per Benchmark den für dich passendensten ermitteln.

Das wäre aber eher ein Backup- und Restore-Verhalten. Für Transaktionen werden i.d.R. Command-Patterns mit Undo/Redo umgesetzt. Das ist zwar etwas aufwändiger, dafür hast du aber die Möglichkeit einzelne Schritte rückgängig zu machen / wiederherstellen anstatt einem alles od. nichts.
Suche mal im Forum danach, da gibt es ein paar Themen und (generische) Ansätze dafür, welche sich leicht integrieren lassen.
Zitat
Das dauert auch teilweise einen Moment, was ich auch gerne verbessern würde weil es die Usability und den Arbeitsfluss stört.
Das passiert hoffentlich asynchron, im Sinne von [FAQ] Warum blockiert mein GUI?

mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
private Nachricht | Beiträge des Benutzers
hypersurf
myCSharp.de - Member



Dabei seit:
Beiträge: 511
Herkunft: Münster

beantworten | zitieren | melden

Wäre das nicht auch ein passender Einsatzzweck für den RecyclableMemoryStream bzw. den RecyclableMemoryStreamManager von Microsoft?
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von hypersurf am .
private Nachricht | Beiträge des Benutzers