AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Extremer Speicherfraß durch Strings/StringLists (?)
Thema durchsuchen
Ansicht
Themen-Optionen

Extremer Speicherfraß durch Strings/StringLists (?)

Ein Thema von nTE · begonnen am 11. Okt 2003 · letzter Beitrag vom 12. Okt 2003
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von nTE
nTE

Registriert seit: 8. Sep 2003
60 Beiträge
 
#1

Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 01:06
Also, mein Problem ist folgendes:

Ich habe ein Programm welches Informationen einliest aus TEmbeddedWB. (ach nee ;)
Mit SaveToStrings speichere ich den Source der Seite in einer TStringList die jedes mal Lokal erstellt und wieder gefreet wird. (Ich bin mir ziemlich sicher, dass ich das try..finally Konstrukt richtig anwende und bei jedem UP-Aufruf wird die Codezeile mit .Free auch abgearbeitet)

Ich verwende sakura's Funktion NextPos um relevante Daten im Source zu finden und lege die in einem Array[1..5] of AnsiString (global) ab. Nach einer bestimmten Anzahl von Aufrufen, speichere ich den Inhalt des Strings in einer Textdatei per Append und mache dann z.B. sMyString[1] := ''; um den String wieder freizugeben.
Mache ich damit schonmal was falsch?
(Und bitte, fragt mich nicht warum ich so'n Scheiss mit dem Array mache, nehmt einfach an es ginge nicht anders. ;)

Tjo, sonst gibt es da noch 2 StringLists, aber die enthalten nicht wirklich viel (max 50KB zusammen) und werden bei Start des Programmes created und bei Beenden gefreet.

Viel mehr Variablen (ausser vielleicht ein bis zwei Schleifenvariablen) habe ich nicht und kann mir nicht erklären, wie das Programm so derbe viel Speicher fressen kann. (Da muss irgendwo ein schwarzes Loch drin sein)

Ich habe es mal eine Stunde laufen lassen (ja, es gab schon einiges zu tun ;) und gegen Ende nutze es 540MB und das Tolle ist, die relevanten Daten, gespeichert in der Textdatei, brauchten am Ende nur ~700KB.


Das ist doch ein erstaunlich großer Unterschied und daher dachte ich mir, frage ich mal hier, vielleicht weiss jemand Rat. Ich kann mir nämlich nur noch an den Kopf fassen.
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.105 Beiträge
 
Delphi 11 Alexandria
 
#2

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 02:16
Moin nTE,

ein bisschen Source wär' nicht schlecht.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Benutzerbild von nTE
nTE

Registriert seit: 8. Sep 2003
60 Beiträge
 
#3

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 08:56
Oh nein, das habe ich befürchet.
Ähm.. also der Code ist wirklich ausgesprochen hässlich und ich hoffe mir ist niemand böse, wenn ich ihn auf das Wesentliche beschränke in der Darstellung hier. :P

Delphi-Quellcode:
procedure Scan(Sender: TObject; sSearchStr);
var
  i, j: Integer;
  sSource: TStringList;
  iPos: Cardinal;
  TempStr: AnsiString;
  DF: Textfile;

begin
  if Sender is TEmbeddedWB then
    begin
      sSource := TStringList.Create;
      try
        with Sender as TEmbeddedWB do
          SaveToStrings(sSource);

        iPos := 0;

        // jetzt kämen zwei for-schleifen :P
        //for i := ...
        //for j := ...
            begin
              iPos := NextPos(sSearchStr, sSourceText, iPos + 1);
              TempStr := Copy(sSource.Text, iPos, 250);

              // kopiert die relevante Information (bis zum nächsten '<')
              // übrigens, da Length Integer und NextPos Cardinal zurückliefert, bekomme ich..
              // ..bei jedem Aufruf dieser Art "Vorzeichenbehaftete und -lose Typen werden kombiniert.."
              // aber dagegen kann ich wohl nichts machen oder? ^^;
              TempStr := Copy(TempStr, 1, Length(TempStr) - (Length(TempStr) - NextPos('<', TempStr, 1) + 1));

              Lines[i] := Lines[i] + TempStr;
              // es folgen weitere 2-3 (je nach if Resultat) solcher Zeilen :P
              // ...
            end;
          // das Speichern des Inhaltes, ab und zu mal (if Verzweigung)
          begin
            for i := 2 to 5 do
              begin
                Lines[1] := Lines[1] + Lines[i];
                Lines[i] := '';
              end;

            AssignFile(DF, SAVE_FILE);
            Append(DF);
            Write(DF, Lines[1]);
            Flush(DF);
            CloseFile(DF);
            Lines[1] := '';
          end;
        with Sender as TEmbeddedWB do
          // URL wird abhängig von den gefundenen Ergebnissen verändert um sich durchzunavigieren :P
          Navigate(URL);
      finally
        sSource.Free;
      end;
    end;
end;
Diese Prozedur wird von TEmbeddedWB.OnDownloadComplete aufgerufen und nachdem ich es mal ein paar Stunden laufen ließ, wurde sie bestimmt an die 40000 Mal aufgerufen.

Mmh.. also ich könnte verstehen wenn euch meine Art meinen Code zu präsentieren gelinde gesagt zu blöd ist, aber ich würde mich trotzdem immer über Hilfe freuen. ;)

[edit=Daniel B]Delphi-Tags korrigiert. Mfg, Daniel B[/edit]
  Mit Zitat antworten Zitat
Ghostwalker

Registriert seit: 16. Jun 2003
Ort: Schönwald
1.299 Beiträge
 
Delphi 10.3 Rio
 
#4

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 09:32
Also.....ich kenn zwar das Problem nicht. Aber 3 Dinge sind mir aufgefallen.

1. Diese Codezeile

Code:
TempStr := Copy(TempStr, 1, Length(TempStr) - (Length(TempStr) - NextPos('<', TempStr, 1) + 1));
der String wird die befüllt (length(tempstr)-length(tempstr)) = 0 - nochwas ergibt negativen wert...!!!


2. sSource wird immer wieder neu erzeugt....-> ineffektiv

Lieber am Programmstart create, am ende free und hier immer nur ssource.clear;


3.Datei

Assign, Append und Close würd ich ebenfalls außerhalb machen. Das frist auch ewig zeit.


Obwohl ich auch einiges mit TStrings/TStringlist mach, hab ich bisher nix feststellen können, das da irgendwelche Speicherleaks auftreten.

Propier mal ob du vielleicht mit dem Programm "Memproof" was rausfindest.

http://www.automatedga.com (memproof)
Uwe
e=mc² or energy = milk * coffee²
  Mit Zitat antworten Zitat
Benutzerbild von nTE
nTE

Registriert seit: 8. Sep 2003
60 Beiträge
 
#5

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 11:03
Erstmal danke für die Antwort, ich habe mir alles mal angeschaut was du gesagt hast (vor allem MemProof) und habe folgendes zu berichten:

Zu 1.
Ich überprüfe vorher (sorry, hab ich nicht aufgeführt) ob iPos > 0 ist (also ob überhaupt was gefunden wurde) und der hintere Teil ist nicht "(length(tempstr)-length(tempstr))" sondern "Length(TempStr) - (Length(TempStr) - NextPos('<', TempStr, 1) + 1)" und daher wird das nie kleiner Null, ausser in ganz TempStr befindet sich kein '<', was ich aber Aufgrund der Kentnisse über die zu erfassende Struktur ausschließen kann. (Es ist sicher immer möglich und schlecht programmiert sowieso, soviel ist sicher =)

Zu 2.
Guter Tipp, habe ich gleich mal geändert.


Zu 3.
Ok, wenn kein Memory mehr leakt, werde ich das alles in einem Schwung in die Datei schreiben (sind ja wie gesagt nur ~700KB). =)


So, erstmal vorneweg, das Programm verwendet schon 6.5 MB nach dem Start.

Ich würde das Speicherloch eindeutig dem Internet Explorer zuschieben.
Wie in der angehangenen Datei zu erkennen, sind die meisten (äh, fast alle?) Fehler beim Speicherfreigeben unter Beteiligung von mshtml.dll und shdocvw.dll.

Ich benutze IE 5.0 unter Win2k mit SP3, d.h. IE 5.00.3502.1000 (128-Bit).
Ich habe schon ein wenig über Leaks im IE 5 gefunden auf der Microsoft-Page aber die sollen angeblich mit IE 5.0 SP3 behoben worden sein.
Müsste ich jetzt auf IE 6 umsteigen (was ich nur seeehr ungern würde) und kann es dabei mit meinem Programm Probleme geben? =)
Angehängte Dateien
Dateityp: rar memproof-log.rar (6,5 KB, 6x aufgerufen)
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.105 Beiträge
 
Delphi 11 Alexandria
 
#6

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 13:12
Moin nTE,

so unmittelbar ist nichts zu sehen
Da ich jetzt TEmbeddedWB nicht habe:
Wo kann ich mal eine Doku zu SaveToStrings nachlesen?
Im Moment habe ich diese Methode im Verdacht.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Benutzerbild von nTE
nTE

Registriert seit: 8. Sep 2003
60 Beiträge
 
#7

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 18:41
Auf der Page steht nur, dass SaveToStrings den Source nach TStrings speichert. :P

Embedded WB Homepage

Daher habe ich mal das Nötige rauskopiert (hoffe ich).

Delphi-Quellcode:
function TEmbeddedWB.SaveToStrings(AStrings: TStrings): HRESULT;
begin
// while ReadyState <> READYSTATE_COMPLETE do
// Forms.Application.ProcessMessages;
  if Assigned(document) then
    Result := SaveDocToStrings(Document, AStrings)
  else Result := S_FALSE;
end;

function SaveDocToStrings(Doc: IDispatch; var AStrings: TStrings): HResult;
var
  IpStream: IPersistStreamInit;
  AStream: TMemoryStream;
begin
  AStream := TMemoryStream.Create;
  try
    IpStream := doc as IPersistStreamInit;
    if not Assigned(IpStream) then Result := S_FALSE else
      if Succeeded(IpStream.save(TStreamadapter.Create(AStream), TRUE))
        then begin
        AStream.Seek(0, 0);
        AStrings.LoadFromStream(AStream);
        Result := S_OK;
      end else Result := S_FALSE;
  except
    Result := S_FALSE;
  end;
  AStream.Free;
end;
In der oberen Funktion habe ich die beiden Codezeilen auskommentiert, da sonst SaveToStrings nie funktioniert, wenn z.B. ein JavaScript ständig den Inhalt ändert (z.B. bei einem Counter oder einer Uhr).
Ausserdem funktioniert SaveFrameToStrings auch ohne das. ;)
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.105 Beiträge
 
Delphi 11 Alexandria
 
#8

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 18:53
Moin nTE,

mal abgesehen davon, dass AStream dort nicht mit einem try/finally Block geschützt ist, bei einer Exception der MemoryStream nicht wieder freigegeben wird, kann ich auch da nichts finden.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Benutzerbild von nTE
nTE

Registriert seit: 8. Sep 2003
60 Beiträge
 
#9

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 19:00
Da ich immer (hab's überprüft ;) einen String zurückbekomme kann man wohl ausschließen, dass eine Exception aufgetreten ist, oder?

Wenn dem so ist, würde ich es echt auf die shdocvw.dll/mshtml.dll schieben. ;)
  Mit Zitat antworten Zitat
Benutzerbild von nTE
nTE

Registriert seit: 8. Sep 2003
60 Beiträge
 
#10

Re: Extremer Speicherfraß durch Strings/StringLists (?)

  Alt 11. Okt 2003, 22:35
Okay, ich habe es einfach mal mit sSource.LoadFromFile als Ersatz probiert (den Rest so gelassen), um festzustellen ob es an SaveToStrings liegt und du hattest Recht Christian, da ist der Wurm drin.

Ich habe mal geschaut was bei TEmbeddedWB so falsch sein könnte und bin bisher nur auf das gestoßen:

Delphi-Quellcode:
constructor TEmbeddedWb.Create(Owner: TComponent);
var
  Buf: array[1..10] of Char;
begin
  FfpExceptions := True;
  inherited;
{$IFDEF VER120}
  enablemessagehandler;
{$ENDIF}
  GetDDEVariables;
  // Compiler: Symbol 'AllocateHWnd' wird abgelehnt
  DDEHWnd := AllocateHWnd(DDEWndProc);
  .
  .
  .
end;

destructor TEmbeddedWb.Destroy;
begin
  // Compiler: Symbol 'DeAllocateHWnd' wird abgelehnt
  DeAllocateHWnd(DDEHwnd);
  .
  .
  .
end;

// Folgendes aus function SaveDocToStrings(Doc: IDispatch; var AStrings: TStrings): HResult;
// mehr Quelltext, siehe oben ;)
IpStream := doc as IPersistStreamInit;
// wird nicht wieder freigegeben? naja, ich hab mal ._Release damit gemacht und es hat nichts gebracht

if Succeeded(IpStream.save(TStreamadapter.Create(AStream), TRUE))
// TStreamadapter hat noch die Eigenschaft Ownership die hier nicht verwendet wird:
// Mit Ownership wird die Eigenschaft StreamOwnership initialisiert, die das verantwortliche TStreamAdapter-Objekt für die Freigabe des in Stream angegebenen Streams im eigenen Destruktor bezeichnet.
//

Mehr fällt mir langsam echt nicht mehr ein. Ich suche momentan noch ein wenig nach Lösungen, aber ich glaube bald lege ich das Programm einfach unter RAM-Hog ab und fass es nicht mehr an. ;)

Ich habe leider keine andere OpenSource TWebBrowser Komponente gefunden, vielleicht hat da ja jemand was für mich? :P


Ach ja, vielleicht könnte ein Mod ja das Thema in "Memory Leak in TEmbeddedWB (SaveTo...)" umbenennen und nach "Internet / IP / LAN" verschieben.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 19:36 Uhr.
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