![]() |
JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Folgendes Szenario. Wir fragen einen JSON Array mit Bildern ab, welcher teilweise über 100MB wird. z.b 20 Dateien a 5MB.
Wenn ich diesen auf Seiten meiner APP in FMX Anfrage wird der Array über 500MB und mit dem umwandeln von JSONValue in TJSONArray knallt mir das Programm mit der Meldung zu wenig Arbeitsspeicher weg ( 32Bit ca 1GB ist Ende ). Auszug aus dem Quellcode :
Code:
Beide Zeilen bei 100MB Input ca 500MB Speicher. und ich kann es auch nicht wirklich umgehen.
var
RESTResponse : TRESTResponse; JSONArray : TJSONArray; jValue : TJSONValue; begin . . jValue := RESTResponse.JSONValue; JSONArray := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(jValue.ToString),0) as TJSONArray; Wenn ich das ganze im RestClient in Firefox anstarte verbraucht Firefox 2,7GB! Frage ist. Gehe ich falsch an das Thema dran? Ich werde nun unsere Aufrufe und Anfragen ändern, so dass ich die Dateien in kleinen Paketen übergebe und nicht einen großen Array. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Na dann kompilier doch mit 64-Bit.
Wenn man meint das man JSON-Daten mit 100 MB hat, dann muss man entweder "rumtrixen" um nicht für 100 MB-Text ein xfaches an Objekten zu haben (Bei xml gäbes es ja Möglichkeiten "beim drüberlesen" nur relative wenige aktive Objektinstanzen zu haben. Alternativ einfach ein 64-Bit Compilierung nehmen. Dann braucht man halt viel RAM - Aber was solls. Dafür ist der RAM ja da. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Effektiv bekommt man in Win32-Programmen (die standardmäßig nur 2 GB haben) ab etwa 700MB Probleme, wenn man versucht das als ein Block in den Arbeitsspeicher zu bekommen.
Denn der kleine Speicher ist fragmentiert ... überall liegen die EXE, DLLs und sonstwas rum. Zusätzlich braucht man beim Laden von "Texten" vorübergehend bis zum 5-fachen als Speicher. z.B. * Datei laden (die Bytes) -> 1x (1 Byte pro Char) * das in einen String konertieren t.B. Bytes mit ANSI drin in einen UnicodeString (TEncoding) -> 2x (2 Byte pro Char) * und dann den String verarbeiten und die Inhalte in Einzelstrings kopieren -> 2x (2 Byte pro Char) 1+2+2 = 5 |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Habt ihr Einfluss auf die Datenquelle?
Wenn ja, müsst ihr überlegen, ob das so gut ist, die großen Binary-Daten per Base64 in ein JSON zu packen. Dafür war das eigentlich nicht gedacht. Sprich: Kann man so machen, aber dann ist es halt kacke. Zum Weiterlesen: ![]() |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
Ggf. brauchst du dadurch auch schon doppelt so viele Ressourcen wie eigentlich nötig, insofern hätte es dann schon etwas mit deinem Problem zu tun. Eigentlich sollte ein...
Delphi-Quellcode:
...völlig reichen und spart Rechenleistung und Speicher.
jValue := RESTResponse.JSONValue;
if jValue is TJSONArray then begin JSONArray := TJSONArray(jValue); // weiteres Zeug hier.. end; |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Danke für die ganzen Antworten.
Die Daten waren am Anfang nicht vorgesehen das sie so groß werden, allerdings pumpt uns nun ein Kunde 5MB JPGs rein und zwar nicht 4-5 sondern 20-50. D.h wie haben nicht direkt Einfluss darauf. Daher habe ich atm auch nur ein 32BIT SDK drauf und wollte vorher prüfen ob es Alternativen gibt. bezüglich dem wandeln in JsonValue. Da war noch eine Abprüfung dazwischen
Code:
das habe ich nun aber umgeschrieben und benötige weniger Speicher. Aber dennoch ist es bei mehr Dateien dann das gleiche Ergebnis.
erg := copy(jValue.ToString,1,10);
if trim(erg) <> '[[null]]' then begin Ich werde nun das ganze umschreiben auf Einzeldateien. Wir haben schon Zugriff auf Script was sendet und das APP was empfängt. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Davon abgesehen, kannst du ggf. ein paar Schritte sparen.
Das folgende gilt für die mir vorliegende Delphi Tokyo Version, kann in späteren Ausgaben also anders aussehen. Du holst dir vom RestResponse per Property JSONValue den geparsten JSON-Text als TJSONValue-Instanz. Wie wir sehen, wird dafür den Inhalt von TCustomRESTResponse.Content erstmal geparst und die TJSONValue-Instanz konstruiert.
Delphi-Quellcode:
Das wird dann innerhalb von TCustomRESTResponse.GetJSONResponse und tiefer in TJSONObject.ParseJSONValue und TJSONObject.ParseValue entsprechend komplexer, aufwendiger und speicherintensiv.
function TCustomRESTResponse.GetJSONValue: TJsonValue;
var LTemp: Boolean; begin Result := nil; if Content <> '' then try GetJSONResponse(Result, LTemp); except // This method ignores exceptions end; end; Dann nimmst du die TJSONValue-Instanz und rufst die ToString Methode auf. Also um das gerade geparste Objekt wieder zu einen String zu konvertieren (Moment, was?). Ich nehme an, wir kommen da in TJSONArray.ToString raus und erzeugen uns hier per TStringBuilder den Rückgabe-String. Ich schlage vor, du versuchst mal folgende zwei Möglichkeiten: 1) Direkte Nutzung von RESTResponse1.Content
Delphi-Quellcode:
var
JSONArray: TJSONArray; JValueAsString: string; JValueAsBytes: TBytes; begin JValueAsString := RESTResponse.Content; JValueAsBytes := TEncoding.UTF8.GetBytes(JValueAsString); JSONArray := TJSONObject.ParseJSONValue(JValueAsBytes, 0) as TJSONArray; end; 2) Direkte Nutzung von RESTResponse1.RawBytes
Delphi-Quellcode:
Ich bin mir an der Stelle nicht sicher, wie sich das da mit dem Encoding verhält.
var
JSONArray: TJSONArray; JValueAsBytes: TBytes; begin JValueAsBytes := RESTResponse1.RawBytes; JSONArray := TJSONObject.ParseJSONValue(JValueAsBytes, 0) as TJSONArray; end; Ihr konvertiert ja nicht ohne Grund explizit nach UTF-8. Aber so als Startpunkt für weitere Optimierung ist das vielleicht schon eine gute Ausgangsbasis. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
|
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Du könntest auf TJSONTextReader umstellen und als Datenlieferant den Response-Stream verwenden.
|
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
Aber vom Prinzip stelle ich das gerade auf einzeln um. Erst die Liste der Dateien und dann die Dateien einzeln. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
Ihr telefoniert doch per REST-Komponenten mit irgendeiner Art Gegenstelle über Netzwerk/Internet, um das Array zu bekommen, richtig? Also bspw. ![]() Kann man das nicht so umändern, dass ihr Zugriff auf das einzelne Item habt? ![]() Und das Image holt ihr euch dann z.B. so: ![]() |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Ja und nein.
Es kann sein das der Webserver und der Fileserver zwei verschiedene Maschinen sind. Dazu trennen wir dies mit Absicht. d.h von aussen kann nur per API/JSON auf Daten zugegriffen und Dateien ausgetauscht werden. Ich hab es nun so gelöst das ich mir erst den JSONArray mit der Filelist und danach die Dateien einzeln herunterlade. Damit sieht der Kunde auch Progress pro Datei. Zugegeben sind 144MB per JSON auszutauschen im WLAN etwas zäh :-) Aber wenn der Kunde 5000x3000 Bilder hochladen muss, dann muss er damit leben. Ist ja nur 1x am Tag. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Binärdaten in JSON sind halt bissl unpraktisch.
ein Schmankl aus DataSnap * das kann Binär oder JSON/REST (der große RAD-Server kann nur JSON) * im JSON ist mehr Traffic und alles wird extrem langsam * * das liegt aber nicht nur daran, dass es selbst bei Base64 33% mehr Daten sind * Bei der Rest-API, wenn als Rückgabewert nur ein "Stream" kommt, dann wird Binär rausgegeben, anstatt JSON (hier wird also die Einschränkung seitens JSON umgangen) * reinzu muß aber alles ins JSON (oder als Parameter in die URL) Wenn das JSON wirklich extrem groß wird, dann muß man eben mit 64 Bit arbeiten, oder man besorgt sich einen JSON-Parser/Reader/Writer, der nicht alles auf einmal ins DOM lädt, sondern stückchenweise einliest/verarbeitet, bzw. speichert. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
Kannst du den Webserver so abändern, dass ihr über die Kette Client -> Webserver -> Fileserver die Dateien holen könnt? Du kannst temporäre Image-URLs verwenden oder die Bilder im Webserver cachen. Beispiel: ![]() NOCHMAL: Ziel ist es nicht, sich eine URL vom Fileserver geben zu lassen, sondern eine direkt vom Client abrufbare URL für die Binärdaten vom Webserver zu erhalten. So spart man sich das ganze Base64 Geraffel und muss dann auch wirklich nur die Bilder laden, die man dann braucht. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Ich bin ehrlich gesagt auf Seiten vom Webserver überfragt was machbar ist und ob das in dem Szenario Sinn ergibt.
Ich spreche es einmal mit dem Mitarbeiter durch welcher bei uns die Webserver administriert. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Nachtrag : Ich versuche mit REST Kompression zu testen, aber irgendwie will das nicht so.
Folgender Artikel ![]() Wir haben in unserem Apache deflate Modul auch eingetragen inkl mod_filter.conf AddOutputFilterByType DEFLATE application/json Aber als Content Encoding erhalte ich immer leer zurück. Bin mir nicht sicher ob das Problem auf Delphi oder Webserver Seite liegt. Wollte daher es mit RESTClient in Firefox testen, aber die haben es deaktiviert. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Das ist keine REST-Kompression, sondern eine Kompression auf dem Transportweg. Das soll dafür sorgen, dass die Daten schneller beim Client landen, ändert aber speziell in deinem Fall nichts an der Größe des Arrays im Speicher.
|
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Hätte ein paar allgemeine Fragen. Du schreibst FMX aber nicht welche Plattform. Könnt/wollt ihr Fremdkomponenten einsetzen? Wie sieht das Schema der JSON-Datei (ein Objekt) aus?
Bis bald... Thomas |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
Das kommt komprimiert rein und wird entpackt, bevor es bei dir landert, wo die Daten/Datenblöcke somit doppelt im Speicher liegen. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
JPEG ist meist auch bereits mehr oder weniger stark komprimiert. Ein Stream Kompressor, der nicht so rumtrödeln darf, wird da nicht so viel bringen.
|
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
Mit der Kompression wollte ich auch eher die Geschwindigkeit des Transports erhöhen oder einmal testen ob es ein Unterschied ergibt. nur mal so. 144MB über 1Gbit Netzwerk ( ca 30 Dateien ) dauern 56sek. Das ist ne Hausnummer. Auf dem Android Tablet was im WLAN hängt dauert es sogar 2min. Auch Test z.b im RESTClient von Firefox ist nicht schneller. Zitat:
|
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
|
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Zitat:
Die meisten unserer Kunden haben auch nur ein paar Dateien und meistens kleinere PNG oder PDF Dateien. Wir haben nur nun einen Kunden der relativ viele Dateien runterlädt. Das ist auch nur ein einmaliger Vorgangs morgens. Wenn der ein paar Minuten dauert ist das aktuell nicht so tragisch. aber ich habe es hier intern schon besprochen das wir dafür eine andere Lösung benötigen. Danke für das ganze Feedback. |
AW: JSONValue zu wenig Arbeitsspeicher bei Array von 100MB
Wie bereits erwähnt, könntest Du mit TJSONTextReader beliebig große Daten sequentiell verarbeiten, ohne das gesamte JSON in mehrere riesige Objekte umwandeln zu müssen. Als Input würde der Responsestream verwendet. Hier ein Beispiel (mit Datei als Input):
Delphi-Quellcode:
var
TextReader : TJsonTextReader; StreamReader : TStreamReader; begin StreamReader := TStreamReader.Create(FFileName); try TextReader := TJsonTextReader.Create(StreamReader); try ConvertSequential(TextReader); finally TextReader.Free; end; finally StreamReader.Free; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:42 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz