Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi temporäre Interfaces sofort freigeben? (https://www.delphipraxis.net/145559-temporaere-interfaces-sofort-freigeben.html)

himitsu 4. Jan 2010 11:48


temporäre Interfaces sofort freigeben?
 
Warum gibt Delphi temporäre Interfaces nicht sofort wieder frei, wenn sie nicht mehr benötig werden?

Bei Strings und dynamischen Arrays versteh ich es ja, da so z.B. der Speicher nochmal verwendet werden kann.

Aber Interfaces verwalten ihren Speicher intern und können ihn garnicht weitergeben,
das heißt, selbst in einer Schleife und in der selben Temp-Variable würden die Interfaces immer wieder "freigegeben" und neu erstellt werden, selbst wenn sie gleich/identisch wären.

aus
Delphi-Quellcode:
for i := 1 to 1000 do
  IntToStr(i);
macht Delphi ja dieses.
Delphi-Quellcode:
var temp: String;

for i := 1 to 1000 do
  temp := IntToStr(i);
Ebenso ist es auch bei Interfaces.

sobald eine Funktion ein Interface als Result zurückliefert oder bei verschachtelten Aufrufen, wird ebenfalls eine temporäre Variable dafür angelegt.

aus [1]
Delphi-Quellcode:
XML.RootDocument.ChildNodes['xyz'].Attributes
wird in etwa dieses [2]
Delphi-Quellcode:
temp1 := XML.RootDocument;
temp2 := temp1.ChildNodes;
temp3 := temp2.Nodes['xyz'];
temp3.Attributes
Das Problem da ist eine beschissene Speicher-/Referenzverwaltung ... vorallem bei verschachtelten Interfaces.
Dadurch wird eventuell nicht alles dort/dann freigegeben, wo man es "vermuten" würde. :wall:


So wurde bei mir z.B. das Document von MSXML dort freigegeben, wo ich es wollte, sondern erst bei Progammende (Consolenanwendung ohne Proceduren und Co., da eh alles Seriell abgearbeitet werden sollte).
Nach einem Hinweis auf dieses Verhalten wurde erstmal jeder größere Schritt in eine Prozedur ausgelagert, wo erstmal dieses Problem verteilt und jeweils bei Prozedurende passierte.

Über 'ne Laufzeitmessung der Prozedurenden, ein massives zerlegen des Codes, eigene temporäre Variablen mit manuell aus-NIL-setzen und vielen Versuchen konnte ich dieses Problem zwar bei mir beheben ... war wichtig 'ne Zeit-/Speichermessung in den einzelnen Programmschritten.

Aber eine gute Lösung ist das nicht wirklich, da der Code so unübersichtlicher wird, wenn man jetzt selber statt [1] nur noch die [2] selber macht.

Alaitoc 4. Jan 2010 12:09

Re: temporäre Interfaces sofort freigeben?
 
Naja so wie ich das sehe werden Interfaces immer dann freigegeben wenn sie nicht mehr verwendet werden.
Wenn man z.b. für IXMLDomDocument eine Membervariable anlegt dann wird sie halt erst freigegeben, wenn
das Objekt an dem sie hängt zerstört wird oder sie explizit auf nil gesetzt wird.

Also in dem Fall:
Delphi-Quellcode:
type
  TBeispiel = class ( TObject )
    private
      m_IXMLDOMDOCUMENT: IXMLDOMDOCUMENT2;
    protected
      { Protected-Deklarationen } 
    public
      { Public-Deklarationen }
  end;
Und wenn sie innerhalb von Methoden verwendet werden, dann werden sie halt am Ende dieser freigegeben ( falls sie nicht irgendwie gesichert wurden z.b. ). Außer man sagt halt wieder explizit das man sie nicht mehr braucht per NIL.

Also in dem Fall:
Delphi-Quellcode:
procedure Beispiel;
var
  IXMLDOMDOCUMENT: IXMLDOMDOCUMENT2;
begin
  IXMLDOMDOCUMENT := coDOMDocument60.Create;
  IXMLDOMDOCUMENT.TUWAS;
end;
Ich halte das soweit für völlig sinnvoll, da Delphi sie halt erst freigibt wenn keine Referenz mehr vorhanden ist.

himitsu 4. Jan 2010 12:18

Re: temporäre Interfaces sofort freigeben?
 
Zitat:

Zitat von Alaitoc
Naja so wie ich das sehe werden Interfaces immer dann freigegeben wenn sie nicht mehr verwendet werden.

Das ist leider ein kleiner aber feiner Irrtum.

Interfaces werden freigegeben, wenn es keine Variablen mehr gibt, wo eine Referenz von ihnen drinsteckt.
(Manipulationen der Referenzzählung mal ausgeschlossen)

[edit]
Beispiel kommt gleich


[edit]
das macht man, bzw. will man machen:
Delphi-Quellcode:
procedure Beispiel;
var
  xml: IXMLDocument;
begin
  xml := coDOMDocument60.Create;
  xml.RootDocument.TUWAS;
  xml := nil; // jetzt würde man denken hier würde alles freigegeben
end; // das passiert aber erst hier
das passiert aber:
Delphi-Quellcode:
procedure Beispiel;
var
  xml: IXMLDocument;
  {$delphiinten} tempnode: IXMLNode; {$ende}
begin
  xml := coDOMDocument60.Create;
  tempnode := xml.RootDocument;
  tempnode.TUWAS;
  xml := nil; // hier passiert nix, da tempnode noch existiert
               // und intern quasi noch eine Referenz auf das Dokument besitzt
end; // hier wird tempnode und erst jetzt erst auch das Dokument freigegeben

Alaitoc 4. Jan 2010 12:19

Re: temporäre Interfaces sofort freigeben?
 
Argh ja :wall: , das versuchte ich damit auszudrücken ^_°

Der Rest stimmt dann aber soweit denk ich x)

MfG Alaitoc

himitsu 4. Jan 2010 12:26

Re: temporäre Interfaces sofort freigeben?
 
Schon OK, im Prinzip stimmt das ja soweit auch.

Nur gibt es da eben dieses klitzekleine Problem ... siehe mein Beispiel in Post #3

sirius 4. Jan 2010 12:53

Re: temporäre Interfaces sofort freigeben?
 
Aber innerhalb einer For-Schleife werden auch die Temps gelöscht
Delphi-Quellcode:
var IntfB:IIntfB;
    i:Integer;
begin

  for i:=1 to 3 do
  begin
    IntfB:=TIntfB.create;
    memo1.lines.add(inttostr(IntfB.IntfA.getNum));
    //IntfB:=nil; mit oder ohne
  end;

Alaitoc 4. Jan 2010 12:56

Re: temporäre Interfaces sofort freigeben?
 
Also wenn ich :

Delphi-Quellcode:
   
if ( GlobalReferenceCount = 0 ) and Assigned( GlobalXMLInterface ) then
    begin
      m_IXMLDocParser := nil; // Hier wird freigegeben
      GlobalXMLInterface := nil; // Hier kann ich nicht mehr auf die geladenen XML-Daten zugreifen
      inherited Destroy;
    end
Oder wie genau überprüfst du das? Hab mir da bisher noch nie so große Gedanken drüber gemacht :gruebel:

Und naja das zweite Beispiel ist mies, da müsste man sich was überlegen...vll irgendwie die Interfaces trennen oder so...

Delphi-Quellcode:
procedure Beispiel;
var
  xml: IXMLDocument;
  {$delphiinten} tempnode: IXMLNode; {$ende}
begin
  xml := coDOMDocument60.Create;
    TuWas(xml.RootDocument);
  xml := nil;          
end;
Da dein Code aber sicherlich um einiges komplexer ist, ist es eine Herausforderung...

himitsu 4. Jan 2010 13:01

Re: temporäre Interfaces sofort freigeben?
 
Zitat:

Zitat von sirius
Aber innerhalb einer For-Schleife werden auch die Temps gelöscht

na das ist ja wohl klar, da dort natürlich immer wieder die selbe Temp-Variable verwendet wird
Delphi-Quellcode:
begin
  xml := coDOMDocument60.Create;
  for i:=1 to 3 do
  begin
    XML.RootDocument.ChildNodes.Nodes['xyz'].Attributes
  end;
  xml := nil;
end;

begin
  xml := coDOMDocument60.Create;
  for i:=1 to 3 do
  begin
    temp1 := XML.RootDocument;
    temp2 := temp1.ChildNodes;
    temp3 := temp2.Nodes['xyz'];
    temp3.Attributes
  end;
  xml := nil;
  // aber das letzte Interface bleibt dennoch bis zum Schluß in diese Variable drinnen.
end;

sirius 4. Jan 2010 13:09

Re: temporäre Interfaces sofort freigeben?
 
Aus irgendwelchen Gründen (vielleicht um es einfach und/oder schnell zu machen) werden lokale (sichtbar oder nicht sichtbar=temporär) Variablen immer am Ende der Funktion gelöscht. Erscheint auch auf den ersten Blick recht logisch.

Und zu deinem Problem:
Tja, himi. Da würde ich sagen: Pech gehabt :stupid:

Im Normalfall ist das Programm derart modularisiert, dass dieses Problem gar nicht erst sichtbar wird. Nur in deinem "Ausnahmefall" hast du ein Problem damit. Was hindert dich daran, dann eben temporäre Variablen sichtbar zu machen (wie du es schon schriebst). Für deinen fall musst du es eben so machen. Tausenden anderen wird dieses durch Delphi erspart.

himitsu 4. Jan 2010 13:19

Re: temporäre Interfaces sofort freigeben?
 
@sirius: ein abschaltbares (gibt ja eh noch nicht genügend geheime Compilerschalter, also kommt es auf einen mehr nicht an) tempvar:=nil; nach gebrauch dieser Interface-Variablen würde vom "Tempo" her nicht viel nehmen und die paar Bytes mehr fallen in den größeren EXEen der neueren Compiler auch nimmer auf,
aber es würde die Speicherverwaltung und Referenzzählung IMHO verbessern.

Die Häufigkeit der Speicherverwaltung und damit das Tempo mag es vielleicht bei Strings und Co. verbessern,
aber bei Interfaces macht dieses eben keinen Unterschied, ob gleich oder erst später.


@Alaitoc:

Aufgefallen ist es praktisch durch dieses
http://www.delphipraxis.net/internal...t.php?t=170881

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

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

local free:[color=#ff0000][b]456[/b][/color]
           [color=#0000ff]^^^ Zeit2[/color]
bei diesem Code kommen die oben genannten Werte raus
- XML:=nil macht nix
- bei Prozedurende wird freigegeben
Delphi-Quellcode:
procedure Test;
  var XML: IXMLDocument;
    Node: IXMLNode;

  begin
    XML := coDOMDocument60.Create;
    XML.Version   := '1.0';
    XML.StandAlone := 'yes';
    XML.Encoding  := 'UTF-8';
    XML.AddChild('xml');
    for i := 0 to 9999 do
      XML.DocumentElement.AddChild(IntToStr(i));
    Start(Zeit1);
    XML := nil;
    Ende(Zeit1);
    Start(Zeit2);
  end;


Test;
Ende(Zeit2);
hier läuft es nun richtig
- bei XML:=nil wird freigegeben
- bei Prozedurende passiert (fast) nix mehr
Delphi-Quellcode:
procedure Test;
  var XML: IXMLDocument;
    Node: IXMLNode;

  begin
    XML := coDOMDocument60.Create;
    XML.Version   := '1.0';
    XML.StandAlone := 'yes';
    XML.Encoding  := 'UTF-8';
    Node2 := XML.AddChild('xml');
    Node2 := nil;
    Node := XML.DocumentElement;
    for i := 0 to 9999 do
      Node2 := Node.AddChild(IntToStr(i));
    Node2 := nil; // oder gleich mit in die Schleife ... ist ja soweit egal
    Node := nil;
    Start(Zeit1);
    XML := nil;
    Ende(Zeit1);
    Start(Zeit2);
  end;


Test;
Ende(Zeit2);


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:03 Uhr.
Seite 1 von 2  1 2      

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