AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein XML Delphi MSXML und seine Speicherverwaltung?

MSXML und seine Speicherverwaltung?

Ein Thema von himitsu · begonnen am 29. Dez 2009 · letzter Beitrag vom 29. Dez 2009
Antwort Antwort
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
39.178 Beiträge
 
Delphi 10.4 Sydney
 
#1

MSXML und seine Speicherverwaltung?

  Alt 29. Dez 2009, 11:52
Moin,

in meinem himXML hab ich unter anderem diesen TestCode (in CheckLibs.dpr)
Delphi-Quellcode:
Var msXML: XMLDoc.TXMLDocument;
   msNode: XMLIntf.IXMLNode;

msXML := XMLDoc.TXMLDocument.Create(nil);
Try
  msXML.DOMVendor := XMLDOM_Vendors[i4].Vendor;
  msXML.Active := True;
  msXML.Version := '1.0';
  msXML.StandAlone := 'yes';
  msXML.Encoding := 'UTF-8';
  msXML.Options := [doNodeAutoIndent];
  msXML.AddChild('xml');
  For i := 0 to 9999 do msXML.DocumentElement.AddChild(Node_IntToStr[i]);
nu hat jemand (samso) rausgefunden, daß dort die Interfaceverwaltung beim SimpleXML schlecht ist ... wodurch einige Objekte (vorallem SimpleXML und auch MSXML) nicht korrekt freigegeben wurden.
Angeblich (laut Messung) ging das superflott innerhalb von etwa 0 ms , aber nun stellte sich raus, daß die Objekte garnicht freigegeben wurden.

Zitat von samso:
Hallo,

ich habe CheckLibs ein wenig überarbeitet. Dabei ging es mir überwiegend um das Testen von SimpleXML. Bei SimpleXML ist es ausgesprochen suboptimal den Knoten sozusagen "offline" zu erzeugen und ihn dann im nächsten Schritt in den XML-Baum einzuklinken. Besser ist die Verwendung von "AppendElement".

Dann bereitet leider das Freigeben der Interfaces ausgesprochenen Ärger. Delphi mag temporäre Interfaces freiwillig erst beim Verlassen der Procedure freigeben. D.h. temporäre Interfaces müssen manuell freigeben werden.
Also so:
Delphi-Quellcode:
siRoot := siXML.DocumentElement;
For i := 0 to 9999 do Begin
  siNode := siRoot.AppendElement(Node_IntToStr[i]);
  siNode := nil;
End;
siRoot := nil;
Statt so:
Delphi-Quellcode:
For i := 0 to 9999 do Begin
  siXML.DocumentElement.AppendElement(Node_IntToStr[i]);
End;
Trotzdem mag Delphi global deklarierte Interfaces irgendwie gar nicht freigeben. Deshalb habe ich alle Tests in entsprechende Proceduren verpackt.
OK, das AppendElement statt meinem CreateXmlElement+AppendChild machte jetzt im Test erstmal keinen großen Unterschied, da AppendElement ebenfalls intern sowas wie CreateXmlElement+InsertChild ausführt.

bei mir sah/sieht es im Testprojekt so aus
Delphi-Quellcode:
For i := 0 to 9999 do Begin
  siNode := SimpleXML.CreateXmlElement(Node_IntToStr[i]);
  siXML.DocumentElement.AppendChild(siNode);
End;
(aber mit dem Hauptproblem der Interfaceverwaltung hat es nichts zu tun)

Zitat von samso:
Jau, schon klar!
Mein Problem war Test 6. Dort wird der Speicher zwischen erzeugen der 3Mio Knoten und dem Lesen der Datei leider nicht freigegeben. Dies führt dann dazu das der Test wegen Speichermangel abgebrochen wird. Deshalb habe ich beide Tests getrennt. Das Verhalten kann man auch bei den anderen Tests erkennen, weil hier das Freigeben üblicherweise in 0ms erfolgt - ergo - es wird nichts freigeben.
D.h. bei globaler Variable:
Zitat:
***** Test 4 ************************************************** ****************

fill TXMLFile with 100.000 nodes, save into and load this from a file
create:0 fill:191 save:109 free:36
create:0 load:409 free:41

fill SimpleXML with 100.000 nodes, save into and load this from a file
create:0 fill:99 save:123 free:0
create:0 load:312 free:0
Bei lokaler Variable
Zitat:
***** Test 4 ************************************************** ****************

fill TXMLFile with 100.000 nodes, save into and load this from a file
create:0 fill:193 save:107 free:37
create:0 load:414 free:36

fill SimpleXML with 100.000 nodes, save into and load this from a file
create:0 fill:109 save:123 free:45
create:0 load:311 free:41

Delphi-Quellcode:
Var msXML: XMLDoc.TXMLDocument;
   msNode: XMLIntf.IXMLNode;

msXML := XMLDoc.TXMLDocument.Create(nil);
Try
  msXML.DOMVendor := XMLDOM_Vendors[i4].Vendor;
  msXML.Active := True;
  msXML.Version := '1.0';
  msXML.StandAlone := 'yes';
  msXML.Encoding := 'UTF-8';
  msXML.Options := [doNodeAutoIndent];
  msNode := msXML.AddChild('xml');
  msNode := nil;
  For i := 0 to 9999 do msNode := msXML.DocumentElement.AddChild(Node_IntToStr[i]);
  msNode := nil;
Nachdem ich nun selber nochmal alles umgestellt und auch mal die Zeit für das Ende ( end. ) der einzelnen Prozeduren mitgemessen hatte, stellte sich der Selbe Effekt auch beim MSXML raus, aber leider komme ich hier nicht weiter

Im Obrigen Code hab ich nurn also mal alle "temporäten" Variablen entfernt, durch eigene ersetzt und diese manuell freigegeben:
Delphi-Quellcode:
Var msXML: XMLDoc.TXMLDocument;
   msNode: XMLIntf.IXMLNode;

msXML := XMLDoc.TXMLDocument.Create(nil);
Try
  msXML.DOMVendor := XMLDOM_Vendors[i4].Vendor;
  msXML.Active := True;
  msXML.Version := '1.0';
  msXML.StandAlone := 'yes';
  msXML.Encoding := 'UTF-8';
  msXML.Options := [doNodeAutoIndent];
  msNode := msXML.AddChild('xml');
  msNode := nil;
  For i := 0 to 9999 do
    msNode := msXML.DocumentElement.AddChild(Node_IntToStr[i]);
  msNode := nil;
so weit so gut ... nur gibt es jetzt ein "klitzekleines" Problem, denn es läuft nichts mehr

msXML läßt sich so nicht als IXMLDokument (Interface) nutzen, da ich noch keine andere Möglichkeit fand dort den DOMVendor anders zu nutzen.

Probem ist jetzt, sobald der Rootnode, welcher von msXML.AddChild('xml') zurückgegeben wird, freigegeben wurde, wird auch das ganze Dokument freigegeben und es kommmt beim Erstellen des ersten Nodes innerhalb der Schleife zu einer Exception.
Zitat:
Im Projekt CheckLibs.exe ist eine Exception der Klasse EXMLDocError mit der Meldung 'Kein aktives Dokument' aufgetreten.
OK, nach etwas Rumprobieren hab ich es nun so
Delphi-Quellcode:
Var msXMLc: XMLDoc.TXMLDocument;
    msXML: XMLIntf.IXMLDocument;
    msNode: XMLIntf.IXMLNode;

msXMLc := XMLDoc.TXMLDocument.Create(nil);
Try
  Try
    msXMLc.DOMVendor := XMLDOM_Vendors[i4].Vendor;
    msXMLc.Active := True;
    msXMLc.Version := '1.0';
    msXMLc.StandAlone := 'yes';
    msXMLc.Encoding := 'UTF-8';
    msXMLc.Options := [doNodeAutoIndent];
  Finally
    msXML := msXMLc;
  End;
  msNode := msXML.AddChild('xml');
  msNode := nil;
  For i := 0 to 9999 do msNode := msXML.DocumentElement.AddChild(Node_IntToStr[i]);
  msNode := nil;
  msXML.SaveToFile(ChangeFileExt(ParamStr(0), '.Test1_MSXML.xml'));
  msXML := nil; // << free
Except
  On E: Exception do Begin
    WriteLn(E.Classname, ': ', E.Message);
    msXML := nil;
  End;
End;
aber auch hier wird das Dokument noch nicht dort Freigegeben wo es sollte (<< free) .

so geht es ebenfalls nicht
Delphi-Quellcode:
msNode := msXML.AddChild('xml');
msNode := nil;
For i := 0 to 9999 do Begin
  msNode := msXML.DocumentElement.AddChild(Node_IntToStr[i]);
  msNode := nil;
End;
msXML.SaveToFile(ChangeFileExt(ParamStr(0), '.Test1_MSXML.xml'));


Code:
***** Test 1 ******************************************************************

fill TXMLFile with 10.000 nodes and save this into a file
create:8  fill:7  save:4  free:3

fill MS-XML-DOM with 10.000 nodes and save this into a file
create:21  fill:13006  save:110  [color=#ff0000]free:0[/color]

[color=#ff0000]local free:456[/color]
Code:
***** Test 1 ******************************************************************

fill TXMLFile with 10.000 nodes and save this into a file
create:0  fill:7  save:6  free:3

[color=#ff0000]local free:0[/color]
ohne MSXML wird die Prozedur schnell beendet, also wurde irgendwas vom MSXML nicht freigegeben
und ich finde einfach nichts mehr ... keine weitere Prozedur hat noch einen Rückgabewert mit 'nem Interface, welche von Delphi als "temporäre" Variable gepsichert und somit erst bei Prozedurende, wo dann auch alle temporären Variablen freigeben werden, welche wie lokale Variablen behandelt werden ... zumindestens finde ich Keine.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014
  Mit Zitat antworten Zitat
samso

Registriert seit: 29. Mär 2009
434 Beiträge
 
#2

Re: MSXML und seine Speicherverwaltung?

  Alt 29. Dez 2009, 18:46
Geht es so?:

Delphi-Quellcode:
msRoot := msXML.AddChild('xml');
For i := 0 to 9999 do Begin
  msNode := msRoot.AddChild(Node_IntToStr[i]);
  msNode := nil;
End;
msXML.SaveToFile(ChangeFileExt(ParamStr(0), '.Test1_MSXML.xml'));
msRoot := nil;
msXML := nil //<- Hier würde ich jetzt das freigeben erwarten
N.B. Zu der Änderung "AppendElement". Dies bezieht sich auf meine geänderte Version von SimpleXML.pas. Bei der alten Version wurde per Default eine globale Namenstabelle benutzt. Das fand ich nicht so toll, weil verschiedene XML-Dateien ja nun nicht unbedingt die gleichen Namen benutzen. Bei meiner Version wird mit einem neuen Dokument auch eine neue Namenstabelle angelegt. Wenn nun ein Element "offline" erzeugt wird, erhält dieses Element eine eigene Namenstabelle. Beim Einhängen des Knotens werden dann die beiden Namenstabellen zusammen geführt. Ein unnötiger Schritt, der bei "AppendElement" vermieden wird. Aber wie gesagt - bezieht sich auf meine Version und nicht auf das Original aus dem Jahr 2003.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
39.178 Beiträge
 
Delphi 10.4 Sydney
 
#3

Re: MSXML und seine Speicherverwaltung?

  Alt 29. Dez 2009, 18:56
Also ... ich bin noch beim Testen, aber der Fehler lag wohl z.B. hier
Code:
msXML.[b]DocumentElement[/b].AddChild
für das verschachtelte DocumentElement legt Delphi auch eine "temporäre" Variable an, welche es nicht gleich wieder freigibt

Und da sage mal wer, daß Interaces soooooo cool wären.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 13:13 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf