Delphi-PRAXiS
Seite 1 von 3  1 23   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   JSON-Serialisierung von generischen Listen nur mit MemoryLeaks (FastMM4) (https://www.delphipraxis.net/182721-json-serialisierung-von-generischen-listen-nur-mit-memoryleaks-fastmm4.html)

DelphiBandit 13. Nov 2014 09:45


JSON-Serialisierung von generischen Listen nur mit MemoryLeaks (FastMM4)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,

ich stehe vor einem mittelprächtigem Problem heute morgen und komme auch nach Stunden des Debuggens kein Stück weiter. Ich habe ein Klassenkonstrukt, welches aus einer JSON-Datei mit Leben gefüllt wird (Einstellungen). Nun kontrollierte ich mittels FastMM4 {$define FullDebugMode} und es bleiben reichlich Speicherlecks. Also eigentlich bleibt so ziemlich alles über, was da reingeladen wurde :o

1.) Im Konstruktor kann man die TObjectList<..>.Create komplett weglassen, diese werden vom JSON-Loader erzeugt
2.) Versuche ich die Objekte vom Typ TObjectList im Destruktor freizugeben bekomme ich einen abstrakten Fehler. Ist im Quelltext momentan auskommentiert, da es eh nur kracht.

Ich habe mir mal ein kleines Testprojekt erzeugt, welches den Sachverhalt mit einer simplen, verschachtelten Klasse nachstellt. Dachte erst es liegt an der Komplexität meiner grossen Klasse und ich habe irgendetwas übersehen. Aber funktioniert auch mit diesem simplen Beispiel nicht korrekt.

Das Testprojekt braucht das Verzeichnis C:\Temp, Populate legt die JSON-Datei an, danach Load und anschliessend Free. Habe das Ganze mal als fertiges Projekt angehängt, allerdings wird FastMM4.pas im Pfad erwartet und steht wiegesagt bei mir auf FullDebug.

Wie werde ich den Speicher wieder los, den mir der JSON-Loader durch dynamische Creates freundlicherweise belegt hat?

Der schöne Günther 13. Nov 2014 10:02

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
(ignoriert mich)

baumina 13. Nov 2014 10:06

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
-- OK, dann ignoriert mich auch :-D --

DelphiBandit 13. Nov 2014 10:08

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
War gerade eine am Hochladen, da fangt Ihr hier mit Eurer "Ignore"-Orgie an :-D

DeddyH 13. Nov 2014 10:10

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
Einfach ignorieren ;)

Der schöne Günther 13. Nov 2014 11:10

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
Elende Ignoranten! :o

Zu den Speicherlecks:

populate
1) In btnPopulateSaveClick wird die lokale entryList nicht freigegeben
2) Der Destruktor von TEntryList gibt seine FEntryLists nicht frei

-> Kein LEck mehr beim fröhligen populieren


load
1) Du überschriebst das FEntryList-Feld deiner Form mit einer neuen Instanz ohne eine evtl
bereits bestehende freizugeben

Weiterhin gibt das Formular sein
Delphi-Quellcode:
FEntryLists
nicht frei. Damit sind wir bei deinem Punkt 2)

Woher der
Delphi-Quellcode:
EAbstractError
kommt verstehe ich auch nicht.

Bei mir (XE7) kracht es dann in

System.Generics.Collections:1111

durch das FArrayManager.Move(..)

FArrayManager ist vom Typ TArrayManager<formHaupt.TEntries>.


Keine Ahnung was da schief läuft. Jemand eine Idee?

Ein "normales"
Delphi-Quellcode:
TObjectList<TEntries>.Create().Free();
klappt ja auch ohne Probleme. Ich hätte gedacht dass der Json-Mechanismus da irgendwie die TObjectList nicht richtig aufbaut...

DelphiBandit 13. Nov 2014 11:34

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
OK, 1) hätte ich Dir/Euch ersparen können :(
Zu 2) Ja, ist ja auskommentiert, weil es nach dem JSON-Load immer knallt. Ansonsten würde sich das Objekt sauber in Wohlgefallen auflösen.

Zu der Form-Variablen FEntryList - die wird nur mit dem "Free"-Button freigegeben. Also quasi auf Anforderung, weil ich dann besser debuggen konnte. "Load" und "Free" (Breakpoint) drücken, also quasi nach dem Motto "Jeder nur ein Kreuz!".

Bei mir in XE5 kommt der abstrakte Error in Generics.Collections beim Zuweisen von Capacity, in der Folge wohl die gleiche Stelle wie bei XE7:

Delphi-Quellcode:
procedure TList<T>.DeleteRange(AIndex, ACount: Integer);
var
  oldItems: array of T;
  tailCount, I: Integer;
begin
  if (AIndex < 0) or (ACount < 0) or (AIndex + ACount > Count)
    or (AIndex + ACount < 0) then
    raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange);
  if ACount = 0 then
    Exit;
 
  SetLength(oldItems, ACount);
  FArrayManager.Move(FItems, oldItems, AIndex, 0, ACount); // Die hier knallt
Ein normales .Free klappt ja auch ohne Speicherlecks, auch bei den Generics. Solange ich nicht zwischendrin das Ganze per REST.Json aus einer Datei habe laden lassen :(

Ich würde, um himitsu's Fußzeile herauszukramen, meinen Müll gerne wegräumen, wenn ich denn wüsste wie :D

Zitat:

Zitat von Der schöne Günther (Beitrag 1279608)
populate
1) In btnPopulateSaveClick wird die lokale entryList nicht freigegeben
2) Der Destruktor von TEntryList gibt seine FEntryLists nicht frei

-> Kein LEck mehr beim fröhligen populieren


load
1) Du überschriebst das FEntryList-Feld deiner Form mit einer neuen Instanz ohne eine evtl
bereits bestehende freizugeben

Weiterhin gibt das Formular sein
Delphi-Quellcode:
FEntryLists
nicht frei. Damit sind wir bei deinem Punkt 2)

Woher der
Delphi-Quellcode:
EAbstractError
kommt verstehe ich auch nicht.


Keine Ahnung was da schief läuft. Jemand eine Idee?

Ein "normales"
Delphi-Quellcode:
TObjectList<TEntries>.Create().Free();
klappt ja auch ohne Probleme. Ich hätte gedacht dass der Json-Mechanismus da irgendwie die TObjectList nicht richtig aufbaut...


Der schöne Günther 13. Nov 2014 13:04

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
Wenn man sich das produzierte JSON ansieht merkt man aber auch dass das Feld
Delphi-Quellcode:
arrayManager
komplett leer ist:
Code:
"arrayManager": {}
Da läuft also was falsch.

Vorhin hatten wir ja auch im Debugger gesehen, dass wir zur Laufzeit (nach dem Zusammenbasteln des Objekts aus dem String) hier einen
Delphi-Quellcode:
TArrayManager<>
haben. Der ist komplett abstrakt. Wir sollten einen
Delphi-Quellcode:
TMoveArrayManager<>
haben.



Ich bin noch kompletter "Delphi vs. JSON"-Anfänger. Kann es sein, dass man dem Automatismus eine
Delphi-Quellcode:
TObjectList<>
schlichtweg nicht anvertrauen darf? Dass er
Delphi-Quellcode:
items
als ein JSON-Array serialisiert sah zwar schon vielversprechend aus, aber über diesen eigentlich unnötigen ArrayManager stolpert er irgendwie...


== PS

Wir entfernen uns hiermit aber auch eigentlich vom Thema Speicherlecks hin zu "Die JSON-Bilbiothek kann keine TObjectList<> serialisieren". Ob man den Titel anpassen sollte?

DelphiBandit 13. Nov 2014 14:16

AW: MemoryLeak (FastMM4) nach Befüllen einer Klasse aus JSON-String
 
Hallo,

ich glaube nicht, dass die Angabe von "arrayManager" im Json-String unnötig ist. Habe ihn gerade in der json-Textdatei mal händisch entfernt. Dann kommt er schon beim Laden damit nicht parat.

Es wäre äußerst bitter, wenn Du Recht hast und man keine generischen Listen aus dem Objekt in einen String und vice versa lesen kann, ohne jedesmal ein massives Speicherleck zu produzieren :evil: Ich benutze das an vielen Stellen in meinem Programm, nicht nur für die Einstellungen. U.a. werden Objekte über das Netz von einem Rechner zum anderen serialisiert. Und die Objekte sind nicht immer so übersichtlich wie in der kleinen Demo hier.

Frage mich dann aber wieder warum es denn eingebaut ist, wenn es nicht fehlerfrei funktionieren sollte? Und das doch schon mal jemanden hätte auffallen müssen (XE5..XE7) und suche den Fehler dann in erster Linie erstmal in meinem Code.

Habe mit einiger Suche jetzt auch noch ein paar Info's dazu gefunden, hier ist auch von MemoryLeaks die Rede und dem Rat auf den Umstieg auf das SuperObject? OMG, wäre das ein Angang :(

http://stackoverflow.com/questions/1...y-method-error
http://www.sdn.nl/SDN/Artikelen/tabi...th-Delphi.aspx

Und hoffe immer noch inständig, das noch eine Idee dazu kommt, um es ohne einen solchen Zusatzaufwand in den Griff zu bekommen. Ach ja, für XE5 sind alle verfügbaren Patches eingepielt, aber das nur am Rande. Die Leaks werden auch ohne FastMM4 beim Beenden des Programms angezeigt. Habe das Archiv eben nochmal erneuert, sollte jetzt so überall lauffähig sein.

Gruß

stoxx 19. Nov 2014 10:15

AW: JSON-Serialisierung von generischen Listen nur mit MemoryLeaks (FastMM4)
 
Zitat:

Zitat von DelphiBandit (Beitrag 1279589)
Wie werde ich den Speicher wieder los, den mir der JSON-Loader durch dynamische Creates freundlicherweise belegt hat?

Hi .. also ein Fehler ist mir auf die Schnelle in "Load" aufgefallen
Das erste erzeugen von FEntrylist ist unnögtig und erzeugt ein Speicherleck, da TJsonToObject das übernimmt.
Geht also auch mit Kommentaren.

Delphi-Quellcode:
 // FEntryList := TEntryList.Create;

  sl := TStringList.Create;
  sl.LoadFromFile('C:\Temp\loading.json');

  try
    FEntryList := TJson.JsonToObject<TEntryList>(sl.Text);


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:10 Uhr.
Seite 1 von 3  1 23   

Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf