Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Hilfe bei Speicherleckbeseitigung (https://www.delphipraxis.net/137824-hilfe-bei-speicherleckbeseitigung.html)

BAMatze 29. Jul 2009 08:35


Hilfe bei Speicherleckbeseitigung
 
Hallo und guten Morgen an alle DP´ler,

Ich bräuchte mal eure Hilfe. Ich bin jetzt schon einige Tage dabei mich genauer mit Speicherlecks in meinem Programm zu beschäfftigen. Leider gibt es hier einige Startschwierigkeiten. Vorallem machen mir die Speicherlecks zu schaffen, die in Folge von TStringLists entstehen.
Gut zu Kern der Geschichte:
Ich habe mir mal eine kleine Funktion herausgesucht, bei der genau die Problematik besteht
Delphi-Quellcode:
unit FestplattenArbeit;

interface

uses Windows, SysUtils, Classes;

Type TFestplattenArbeit = class(TComponent)
  private
    FsLInfoeinfachLaufwerke: TStringList;
    function DriveExists(DriveByte: Byte): Boolean;
    procedure simpleDriveSearch(var LaufwerkList: TStringList);
    function GetLaufwerksanzahl: integer;
  protected
  public
    constructor create(AOwner: TComponent); reintroduce;
    destructor Destroy; //override;
    property Count: integer read GetLaufwerksanzahl;
    property FestplattenListe: TStringlist read FsLInfoeinfachLaufwerke;
end;

implementation

{////////////////////////////////////////////////////////////////////////////////////}
{/                              create und destroys                                /}
{////////////////////////////////////////////////////////////////////////////////////}

constructor TFestplattenArbeit.create(AOwner: TComponent);
begin
  inherited create(AOwner);
  FsLInfoeinfachLaufwerke := TStringList.Create;
  simpleDriveSearch(FsLInfoeinfachLaufwerke);
end;

destructor TFestplattenArbeit.destroy;
begin
  while FsLInfoeinfachLaufwerke.Count > 0 do FslInfoeinfachLaufwerke.Delete(0);
  FsLInfoeinfachLaufwerke.Free;
  inherited destroy;
end;

{////////////////////////////////////////////////////////////////////////////////////}
{/                              private Funktionen                                 /}
{////////////////////////////////////////////////////////////////////////////////////}

function TFestplattenArbeit.DriveExists(DriveByte: Byte): Boolean;
begin
  Result := GetLogicalDrives and (1 shl DriveByte) <> 0;
end;

procedure TFestplattenArbeit.simpleDriveSearch(var LaufwerkList: TStringList);
var Index: Integer;
begin
  for Index := 0 to 25 do if DriveExists(Index) then LaufwerkList.Add(Chr(Index + Ord('A')) + ':\');
end;

{////////////////////////////////////////////////////////////////////////////////////}
{/                              Getter und Setter                                  /}
{////////////////////////////////////////////////////////////////////////////////////}

function TFestplattenArbeit.GetLaufwerksanzahl: integer;
begin
  result := FsLInfoeinfachLaufwerke.Count;
end;

end.
Crosspost: Hier wurde schonmal ein Teil der Unit gepostet.

Diese Unit verursacht bei mir genau 8 Speicherlecks (Diese 8 Fehler ergeben sich aufgrund der Anzahl an gefundenen Fesplatten!! kann also im Einzelfall auf anderen Rechnern variieren). Wie DeddyH im Crosspost richtig bemerkt hat, stammen die nicht wie von mir vermutet von der DriveExist-Funktion, sondern sind mit der TStringList direkt verbunden. Allerdings stoße ich hier erstmal auf gewisse Grenzen, wie ich diese Fehler korrigieren kann.
Aus anderen Threats habe ich mitbekommen, dass man bevor die TStringlist freigegeben werden kann, alle "Einzeleinträge" löschen/ freigeben muss (dies erscheint auch logisch da anscheinend jeder Eintrag an sich schon ein Objekt darstellt und somit je mehr Einträge/ Objekte in meiner Liste sind, desto mehr Speicherlecks habe ich). Die Frage ist eigentlich jetzt und dies habe ich irgendwie noch nirgends als richtigen "Lösungsweg" gefunden, Wie gebe ich die Einträge in einer TStringList richtig frei, damit das TStringlist.free ebenfalls meine Liste freigeben kann?

Folgendes habe ich schonmal versucht:
Delphi-Quellcode:
  // Versuch jeden einzelnen Beitrag zu löschen, bis keiner mehr da ist -> wirkungslos, Fehlerzahl bleibt konst
  while FsLInfoeinfachLaufwerke.Count > 0 do FslInfoeinfachLaufwerke.Delete(0);
  // Versuch die gesamte Liste zu löschen -> wirkungslos, Fehlerzahl bleibt konst
  FsLInfoeinfachLaufwerke.clear;
Eine Alternative, bei der ich aber noch nicht weiß, wie man sie einsetzen kann, wäre wohl eine TObjectList. Diese schien bei vielen Threats die einzige Lösung zu sein um kein Speicherleck zu erzeugen. Aber dort bleibt für mich die Frage, ist sowas wirklich nötig/ sinnvoll, wenn ich nur eine Problemursache habe, etwas neues für die Verwaltung diese Objektes aufzumachen? Allerdings würde mich schon (für meine größeren Units) mal interessieren, wie sowas aussieht.

Vielen Dank
BAMatze

mleyen 29. Jul 2009 09:05

Re: Hilfe bei Speicherleckbeseitigung
 
Zitat:

Zitat von BAMatze
Delphi-Quellcode:

//...
type TFestplattenArbeit = class(TComponent)
//...
    destructor Destroy; override;

//...

destructor TFestplattenArbeit.Destroy;
begin
  FsLInfoeinfachLaufwerke.Free;
  inherited destroy;
end;

Hi,

hat es einen Grund warum du das override auskommentiert hast?
Wenn ich das override hinmache gibts bei mir keinen Speicherleck. Was soll der auch 'destroyen' wenn der etwas falsches inherited?

Edit: Wenn du override wegläst, optimiert mir der Compiler das inherited komplett weg...

Satty67 29. Jul 2009 09:08

Re: Hilfe bei Speicherleckbeseitigung
 
€: mleyen war schneller

BAMatze 29. Jul 2009 09:45

Re: Hilfe bei Speicherleckbeseitigung
 
Ah danke, war genau das richtige. Das auskommentieren stammt eigentlich noch von einem anderen Versuch, dumm das :evil: .

Vieleicht hat aber jemand doch noch eine Antwort auf die Frage mit der TObjectList.

Banke für die schnelle Hilfe.

hoika 29. Jul 2009 10:00

Re: Hilfe bei Speicherleckbeseitigung
 
Hallo,

TObjectList verwaltet Objekte und gibt sie beim Free auch frei
(wenn OwnsObjects True ist).


Heiko

Carsten1234 29. Jul 2009 10:06

Re: Hilfe bei Speicherleckbeseitigung
 
Zitat:

Zitat von BAMatze
Vieleicht hat aber jemand doch noch eine Antwort auf die Frage mit der TObjectList.

Was genau interessiert Dich daran? Wie das aussieht?

Delphi-Quellcode:

  TSingle = class(TObject)
    Datum      : string;
    Uhrzeit    : string;
    Name       : string;
    Rufnummer  : string;
  end;

  TMyObjectList = class(TObjectList)
  private
    FKeineAhnung: integer;
  public
    property KeineAhnung: integer read FKeineAhnung write FKeineAhnung;
  end;
und dann (z.B. im FormCreate):
Delphi-Quellcode:
MyObjectList:= TMyObjectList.Create;
Nicht vergessen, die Liste beim Schließen wieder freizugeben:
Delphi-Quellcode:
MyObjectList.Free;
Füllen mit:
Delphi-Quellcode:
var Single: TSingle;
begin
  for x:= 1 to 10 do
  begin
    Single:= TSingle.Create;
    Single.Datum:= ...
    Single.Uhrzeit:= ...
    MyObjectList.Add(Single);
  end;
end;
Auslesen mit:
Delphi-Quellcode:
var Single: TSingle;
begin
  Single:= MyObjectList.Items[0] as TSingle;
end;
Gruß, Carsten

BAMatze 29. Jul 2009 10:08

Re: Hilfe bei Speicherleckbeseitigung
 
@carsten jupp das war´s was mich mal interessiert hat :mrgreen:

thanks

Blup 30. Jul 2009 08:38

Re: Hilfe bei Speicherleckbeseitigung
 
Delphi-Quellcode:
while FsLInfoeinfachLaufwerke.Count > 0 do FslInfoeinfachLaufwerke.Delete(0);
FsLInfoeinfachLaufwerke.Free;
Die Schleife ist überflüssig, um die Freigabe der Strings kümmert sich die TStringList im Destructor selbst. Ebenso kümmert sich die TObjectList um die Freigabe der enthaltenen Objekte, wenn OwnsObjects = True (Standard).

nahpets 30. Jul 2009 10:45

Re: Hilfe bei Speicherleckbeseitigung
 
Hallo,

warum
Delphi-Quellcode:
procedure TFestplattenArbeit.simpleDriveSearch(var LaufwerkList: TStringList);
var Index: Integer;
begin
  for Index := 0 to 25 do if DriveExists(Index) then LaufwerkList.Add(Chr(Index + Ord('A')) + ':\');
end;
und nicht
Delphi-Quellcode:
procedure TFestplattenArbeit.simpleDriveSearch;
var Index: Integer;
begin
  for Index := 0 to 25 do if DriveExists(Index) then FslInfoeinfachLaufwerke.Add(Chr(Index + Ord('A')) + ':\');
end;
Stringliste und Prozedur gehören doch zu einer Klasse, da muss die Stringliste doch nicht als Parameter an die Prozedur übergeben werden.

Oder habe ich da was übersehen?

BAMatze 31. Jul 2009 07:17

Re: Hilfe bei Speicherleckbeseitigung
 
Zitat:

Zitat von nahpets
Stringliste und Prozedur gehören doch zu einer Klasse, da muss die Stringliste doch nicht als Parameter an die Prozedur übergeben werden.
Oder habe ich da was übersehen?

Nö hast Recht, ist wohl noch ein Überbleibsel meiner TP-Zeit in der Schule :mrgreen: also schon lange her.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:13 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