AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign JSON-Serialisierung von generischen Listen nur mit MemoryLeaks (FastMM4)
Thema durchsuchen
Ansicht
Themen-Optionen

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

Ein Thema von DelphiBandit · begonnen am 13. Nov 2014 · letzter Beitrag vom 20. Nov 2014
Antwort Antwort
Benutzerbild von DelphiBandit
DelphiBandit

Registriert seit: 19. Feb 2007
Ort: In der Lüneburger Heide
165 Beiträge
 
Delphi 10.4 Sydney
 
#1

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

  Alt 13. Nov 2014, 09:08
War gerade eine am Hochladen, da fangt Ihr hier mit Eurer "Ignore"-Orgie an
Carsten
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.666 Beiträge
 
Delphi 12 Athens
 
#2

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

  Alt 13. Nov 2014, 09:10
Einfach ignorieren
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.210 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

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

  Alt 13. Nov 2014, 10:10
Elende Ignoranten!

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 FEntryLists nicht frei. Damit sind wir bei deinem Punkt 2)

Woher der 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" TObjectList<TEntries>.Create().Free(); klappt ja auch ohne Probleme. Ich hätte gedacht dass der Json-Mechanismus da irgendwie die TObjectList nicht richtig aufbaut...
  Mit Zitat antworten Zitat
Benutzerbild von DelphiBandit
DelphiBandit

Registriert seit: 19. Feb 2007
Ort: In der Lüneburger Heide
165 Beiträge
 
Delphi 10.4 Sydney
 
#4

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

  Alt 13. Nov 2014, 10:34
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

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 FEntryLists nicht frei. Damit sind wir bei deinem Punkt 2)

Woher der EAbstractError kommt verstehe ich auch nicht.


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

Ein "normales" TObjectList<TEntries>.Create().Free(); klappt ja auch ohne Probleme. Ich hätte gedacht dass der Json-Mechanismus da irgendwie die TObjectList nicht richtig aufbaut...
Carsten
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.210 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

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

  Alt 13. Nov 2014, 12:04
Wenn man sich das produzierte JSON ansieht merkt man aber auch dass das Feld 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 TArrayManager<> haben. Der ist komplett abstrakt. Wir sollten einen TMoveArrayManager<> haben.



Ich bin noch kompletter "Delphi vs. JSON"-Anfänger. Kann es sein, dass man dem Automatismus eine TObjectList<> schlichtweg nicht anvertrauen darf? Dass er 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?

Geändert von Der schöne Günther (13. Nov 2014 um 12:40 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DelphiBandit
DelphiBandit

Registriert seit: 19. Feb 2007
Ort: In der Lüneburger Heide
165 Beiträge
 
Delphi 10.4 Sydney
 
#6

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

  Alt 13. Nov 2014, 13:16
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 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ß
Carsten

Geändert von DelphiBandit (13. Nov 2014 um 14:04 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stoxx
stoxx

Registriert seit: 13. Aug 2003
1.111 Beiträge
 
#7

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

  Alt 19. Nov 2014, 09:43
<noch nicht ganz korrekte Fehlerbeschreibung> (daher beitrag gelöscht)
Phantasie ist etwas, was sich manche Leute gar nicht vorstellen können.

Geändert von stoxx (19. Nov 2014 um 09:49 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.752 Beiträge
 
Delphi 12 Athens
 
#8

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

  Alt 19. Nov 2014, 11:00
Das hat wohl keine Relevanz, aber das Property SecondClassEntries verweist auf das falsche Feld.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von DelphiBandit
DelphiBandit

Registriert seit: 19. Feb 2007
Ort: In der Lüneburger Heide
165 Beiträge
 
Delphi 10.4 Sydney
 
#9

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

  Alt 19. Nov 2014, 11:09
Danke für den Hinweis Uwe. Das habe ich durch Blick in die json-Datei auch schon bemerkt und in der "aktuellen" Version des kleinen Testprogramms korrigiert.

Habe auch die bisherigen Info's von stoxx mit eingearbeitet (2 x FEntryList). Der abstrakte Error ist jetzt weg, aber das Speicherleck bleibt nach wie vor erhalten, weil die destructor-Routinen der untergeordneten Objekte beim .Free des aus json erzeugten Objektes nicht aufgerufen werden. Nach Erzeugung durch den überladenen Konstruktor wird jetzt zwar TEntryList.destroy ohne abstrakten Fehler aufgerufen, die enthaltene Liste FEntryLists ist aber (bereits?) nil.

Werde das Archiv mal eben aktualisieren. Schade geht nicht, kann den ersten Beitrag nicht mehr bearbeiten Also dann hier dran.
Angehängte Dateien
Dateityp: zip SimpleJSONLeak.zip (23,3 KB, 8x aufgerufen)
Carsten

Geändert von DelphiBandit (19. Nov 2014 um 12:35 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stoxx
stoxx

Registriert seit: 13. Aug 2003
1.111 Beiträge
 
#10

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

  Alt 19. Nov 2014, 13:18
also nun nochmal komplett.

im Anhang eine Version ohne Speicherleck.
Zum einen ist zu beachten, dass eine Objectlist keine TCollection ist, also die Elemente der Liste müssen manuell selbst im Destructor gelöscht werden.
Delphi hat aber ein Bug in "DeleteRange" in TList<> und TObjectList<>, welcher den Abstrakten Fehler erzeugt.
Umgehen kann man ihn, indem man jedes Element einzeln im Destructor löscht. (absteigend durchgehen)
Erzeugung über JSON jetzt besser über eine class function.

Im Anhang ein funktionierendes Projekt (ohne Speicherlecks)

Delphi-Quellcode:
destructor TObjectsTEntry.destroy;
var i : Integer;
    entry : TEntry;
begin
  for i := self.Count-1 downto 0 do begin
    entry := self.Items[i];
    entry.Free;
    self.Delete(i);
  end;
  self.Clear;
  inherited;
end;

Delphi-Quellcode:
class function TEntryList.Create(aJSON: string) : TEntryList;
begin
  result := TJson.JsonToObject<TEntryList>(aJSON);
end;
Angehängte Dateien
Dateityp: rar SimpleJSONLeak.rar (6,0 KB, 11x aufgerufen)
Phantasie ist etwas, was sich manche Leute gar nicht vorstellen können.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:43 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-2025 by Thomas Breitkreuz