AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Funktion verursacht Memory-Leak >>> Warum ?
Thema durchsuchen
Ansicht
Themen-Optionen

Funktion verursacht Memory-Leak >>> Warum ?

Ein Thema von jensw_2000 · begonnen am 30. Jun 2006 · letzter Beitrag vom 1. Jul 2006
Antwort Antwort
jensw_2000
(Gast)

n/a Beiträge
 
#1

Funktion verursacht Memory-Leak >>> Warum ?

  Alt 30. Jun 2006, 20:22
Hi,
folgende Funktion wird in meinem Programm einige 100000 mal pro Tag aufgerufen. Das Programm belegt morgens nach dem Start etwa 17 MB. Abends belegt das Tool etwa 80 MB.

Folgende Funktion scheint dafür verantwortlich zu sein ...

CallJob.Rufnummer := RemoveChars(CallJob.Rufnummer);
Delphi-Quellcode:
function RemoveChars(Rufnummer: string): string;
var i: Integer;
begin
  result := '';

  if length(Rufnummer) = 0 then exit;

  Rufnummer := stringreplace(Rufnummer, '+', '00', []);

  for i := 0 to length(Rufnummer) do
    if Rufnummer[i] in ([#48..#57]) then result := result + Rufnummer[i];

  Setlength(Rufnummer,0);   

end;
Offensichtlich wird irgend ein String nicht aus dem Speicher entfernt.
Wenn ich den Funktionsaufruf "CallJob.Rufnummer := RemoveChars(CallJob.Rufnummer);" auskommentiere, ist das Speicherleck weg ...

Wo und Wie kann ich den Stringspeicher wieder sauber freigeben ?
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.171 Beiträge
 
Delphi 10.4 Sydney
 
#2

Re: Funktion verursacht Memory-Leak >>> Warum ?

  Alt 30. Jun 2006, 20:26
Las mal den Setlength-Aufruf weg und die Schleife sollt auch von 1 beginnen.
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#3

Re: Funktion verursacht Memory-Leak >>> Warum ?

  Alt 30. Jun 2006, 20:48
ein "anfälliger" Programmierstil den du hast

Delphi-Quellcode:
function RemoveChars(const Rufnummer: String): String;
var
  I: Integer;
  R,T: String;
begin
  R := '';
  if Rufnummer <> 'then
  begin
    T := StringReplace(Rufnummer, '+', '00', []);
    for I := 1 to Length(T) do
      if T[I] in ['0'..'9'] then
        R := R + T[I];
  end;
  Result := R;
end;
Was auffällt ist die klarere Struktur einer modularen Programmierung. Das heist klare Eingabeparameter die readonly/konstant sind, klare lokale Variablen in denen das Prozessing stattfindet und klare Ausgabeparameter die am Schluß der Funktion erst gefüllt werden, quasi-konstant.
Dann die Benutzung struktutierter Bedingungen, statt einem Exit also ein Begin End Block.
Und die Benutzung lesbarer Char Konstanten in der in [] Abfrage, was im Gewgensatz zu #48 und #57 oder wenigsten #$30 und #$39 weit intuitiver ist. Diese Kleinigkeiten machen alles verständlicher und wir als Programmierer können das bischen Glukose in unserem Hirn auf die logische Fehlervermeidung konzentrieren.

Klar, es gibt nun noch Optimierungen zu Gunsten der Performance, aber das ist für dein Problem erstmal irrelevant.
Zb.

Delphi-Quellcode:
function RemoveChars(const Rufnummer: String): String;
var
  I,J: Integer;
  R: String;
begin
  R := '';
  if Rufnummer <> 'then
  begin
    J := 0;
    SetLength(R, Length(Rufnummer) * 2); // doppelte Länge preallozieren, bei '+' Substitution mit '00' ergo 1 zu 2
    for I := 1 to Length(Rufnummer) do
      if Rufnummer[I] in ['0'..'9'] then
      begin
        Inc(J);
        R[J] := T[I];
      end else
        if Rufnummer[I] = '+then
        begin
          R[J +1] := '0';
          R[J +2] := '0';
          Inc(J, 2);
        end;
    SetLength(R, J);
  end;
  Result := R;
end;
Diese Funktion prealloziert den LongString in R schon im vorhinein. Statt per Konkatenation -> R := R + x nun viele Reallozierungen dieses String durchzuführen (jedesmal ein Aufruf zum Speichermanager und auch Kopieren dieses Speicherbereich), kopieren wir nur noch das entsprechende Zeichen. Am Schluß setzen wir die Länge von R nur noch auf die Anzahl tatsächlich kopierter Zeichen. Das dürfte in der Peformance weitaus effizienter sein.


Gruß Hagen
  Mit Zitat antworten Zitat
jensw_2000
(Gast)

n/a Beiträge
 
#4

Re: Funktion verursacht Memory-Leak >>> Warum ?

  Alt 30. Jun 2006, 21:42
Ich habe alle 3 Varianten getestet (Korrektur meiner Funktion und die beiden von Hagen).
Das Problem scheint weiterhin zu bestehen.

Mit dem Aufruf von RemoveChars nimmt der belegte Speicher stätig zu.
(nach 5.000 Durchläufen rund 0,5 MB, nach 30.000 Durchläufen knapp 1 MB)
Ohne den Funktionsaufruf bleibt der belegte Arbeitsspeicher nahezu konstant bei 17,5 MB.

Ist es relevant, asynchron aus mehreren Threads aufgerufen wird ?
  Mit Zitat antworten Zitat
omata

Registriert seit: 26. Aug 2004
Ort: Nebel auf Amrum
3.154 Beiträge
 
Delphi 7 Enterprise
 
#5

Re: Funktion verursacht Memory-Leak >>> Warum ?

  Alt 30. Jun 2006, 22:38
_
  Mit Zitat antworten Zitat
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#6

Re: Funktion verursacht Memory-Leak >>> Warum ?

  Alt 30. Jun 2006, 22:45
Also an deiner RemoveChars Funktion kann es nicht liegen (wenn du die Zählervariable I auf 1 gesetzt hast).

Meine Vermutung ist nun folgende:
Du benutzt diese Funktion in einem Thread. Diese Funktion ist in diesem Thread die Einzigste die mit LongStrings arbeitet, also Speicher beim Speichermanager anfordert. Und nun, ich vermute du nutzt einen anderen Speichermanager ! sowas wie FastMM (wobei der im Grunde sauber ist). Es gibt aber auch andere MMs die eben gerade bei Threads versprechen schneller zu sein als der Borland eigene und das nur erreichen weil sie für jeden Thread separate MMs installieren die aber bei Beendigung der Threads nicht terminiert werden. Also, könnte es sein das du einen anderen MM installiert hast ?

Ansonsten wüsste ich keine Erklärung ohne deinen Source des Threads gesehen zu haben.

Gruß Hagen
  Mit Zitat antworten Zitat
jensw_2000
(Gast)

n/a Beiträge
 
#7

Re: Funktion verursacht Memory-Leak >>> Warum ?

  Alt 1. Jul 2006, 01:59
@Hagen
Ich habe mit vor einigen Tagen zur Fehlersuche FastMM 4 installiert und "RemoveChars" ist in der Tat das Einzige Aufruf einer Thread-externen Funktion, bei dem LongStrings als Parameter verwendet werden.
Die Threads werden beim Dienststart erzeugt und beim Dienst-Stop beendet und freigegeben. Das Grundgerüst habe ich auf Alzaimar's genialem Threads & Jobs Beispiel aufgebaut.
Die Jobs sind einfache Objekte, welche u.A. 2 Longstrings enthalten. Die Job-Objekte befinden sich in einer TObjectlist und werden mittels TObjectlist.Extract von einem freien WorkerThread abgeholt. Der WorkerThread liest als erstes die Werte aus dem Job-Objekt in (Thread-)lokale Variablen ein und gibt das Job-Objekt sofort frei.
Dannach werden die Daten durch ein an den Thread gebundenes COM Objekt bearbeitet und letztlich in einer DB gespeichert. Der Workerthread wieder "inaktiv" extrahiert dann das nächste freie Job-Object aus der Jobliste.

Ich baue am Sonntag den Borland MM wieder ein und mache ein paar einen Testläufe.
Hoffentlich erledigt sich das Leak-Problem damit.

Erstmal vielen Dank für deine Hilfe.


Schöne Grüße,
Jens
  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 19:06 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