Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Speicherleck oder nicht bzw. wer findet den Fehler? (https://www.delphipraxis.net/31927-speicherleck-oder-nicht-bzw-wer-findet-den-fehler.html)

phlux 15. Okt 2004 18:30


Speicherleck oder nicht bzw. wer findet den Fehler?
 
Servus :hi:
Hab schon laaange zeit nicht mehr gecodet deshalb passieren mir im Moment ziemlich dumme Fehler :roll: trotzdem hätt ich hier eine Frage mal zu klären.
:arrow: Also ich habe ein Objekt
Delphi-Quellcode:
type
  TWasteItem = class(TComponent)
  private
    { Private-Deklarationen }
    // ...
  published
    { Published-Deklarationen }
    // ...
  end;
:arrow: Dann erzeuge ich mit folgender Prozedur einen Dialog der zusätzlich eine property Waste: TWasteItem hat
Delphi-Quellcode:
procedure TMainForm.ShowItemDlg(Item: TWasteItem);
var
 ItemDlg: TItemDlg;

begin
  ItemDlg := TItemDlg.Create(Self);
  try
    If Item <> nil then
      ItemDlg.Waste := Item;
    ItemDlg.ShowModal;
  finally
    ItemDlg.Free;
  end;
end;
:arrow: Jetzt will ich dem Dialog genau so ein Typ übergeben
Delphi-Quellcode:
procedure TMainForm.btnDBEditClick(Sender: TObject);
var
  wItem: TWasteItem;

begin
  wItem := TWasteItem.Create(Self);
  try
    ShowItemDlg(wItem);
  finally
//    wItem.Free;
  end;
end;
Mein Problem ist jetzt wenn man wItem.Free nicht auskommentiert dann kommts zu ner Exception :x Lass ich das Free weg geht alles reibungslos nur dadurch entsteht dann doch ein Speicherleck weil ich den reservierten Speicher nicht mehr freigebe oder? Wäre nett wenn mir mal einer den richtigen Weg zeigen würde ;)

mfg phluphie :hi:

Gruber_Hans_12345 15. Okt 2004 18:33

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
Kannst du den Code vom TItemDlg posten (Events wie FormCreate, Destroy, Close usw)
gibst du dort irgendwo Wast frei ?

phlux 15. Okt 2004 18:37

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
Okay hier ist der Code von der DialogForm ;)

Delphi-Quellcode:
unit frmItemDlg;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, JvExStdCtrls, JvEdit, Buttons, Mask,
  JvExMask, JvBaseEdits, JvValidateEdit, JvDatePickerEdit,
  JvCheckedMaskEdit, JvMaskEdit, JvToolEdit, WasteItem;

type
  TItemDlg = class(TForm)
    Panel1: TPanel;
    Bevel1: TBevel;
    Label1: TLabel;
    Label2: TLabel;
    Image1: TImage;
    GroupBox1: TGroupBox;
    Label5: TLabel;
    edTrans: TJvValidateEdit;
    edDisp: TJvValidateEdit;
    edOverall: TJvValidateEdit;
    Label6: TLabel;
    Label8: TLabel;
    Bevel2: TBevel;
    btnCancel: TButton;
    btnOK: TButton;
    GroupBox2: TGroupBox;
    Label3: TLabel;
    ItemList: TComboBox;
    DatePicker: TJvDatePickerEdit;
    Label7: TLabel;
    edWeight: TJvValidateEdit;
    Label4: TLabel;
    procedure btnCancelClick(Sender: TObject);
    procedure edOverallEnter(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ItemListKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure btnOKClick(Sender: TObject);
  private
    { Private-Deklarationen }
    fPath: String;
    fItems: TStringList;
//  protected
    fWasteItem: TWasteItem;
  public
    { Public-Deklarationen }
    property Waste: TWasteItem read fWasteItem write fWasteItem;
  end;

var
  ItemDlg: TItemDlg;

implementation

{$R *.dfm}

procedure TItemDlg.btnCancelClick(Sender: TObject);
begin
  ModalResult := mrCancel;
end;

procedure TItemDlg.FormCreate(Sender: TObject);
begin
  fPath := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
  fItems := TStringList.Create;
  fWasteItem := TWasteItem.Create(Self);
  If FileExists(fPath + 'waste.itm') then
  begin
    ItemList.Items.LoadFromFile(fPath + 'waste.itm');
  end;
end;

procedure TItemDlg.FormDestroy(Sender: TObject);
begin
  ItemList.Items.SaveToFile(fPath + 'waste.itm');
  fWasteItem.Free;
  fItems.Free;
end;

procedure TItemDlg.btnOKClick(Sender: TObject);
begin
  fWasteItem.WasteType := ItemList.SelText;
  fWasteItem.Weight := edWeight.Value;
  fWasteItem.TransportCost := edTrans.Value;
  fWasteItem.DisposalCost := edDisp.Value;
  fWasteItem.Date := DatePicker.Date;
  ModalResult := mrOK;
end;

end.
Ich habe mir mal erlaubt die unrelevanten Teile (StringListe in eine Combobox laden&speichen) zu entfernen.

Gruber_Hans_12345 15. Okt 2004 18:40

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
Zitat:

Zitat von phlux
Okay hier ist der Code von der DialogForm ;)

Delphi-Quellcode:
unit frmItemDlg;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, JvExStdCtrls, JvEdit, Buttons, Mask,
  JvExMask, JvBaseEdits, JvValidateEdit, JvDatePickerEdit,
  JvCheckedMaskEdit, JvMaskEdit, JvToolEdit, WasteItem;

type
  TItemDlg = class(TForm)
    Panel1: TPanel;
    Bevel1: TBevel;
    Label1: TLabel;
    Label2: TLabel;
    Image1: TImage;
    GroupBox1: TGroupBox;
    Label5: TLabel;
    edTrans: TJvValidateEdit;
    edDisp: TJvValidateEdit;
    edOverall: TJvValidateEdit;
    Label6: TLabel;
    Label8: TLabel;
    Bevel2: TBevel;
    btnCancel: TButton;
    btnOK: TButton;
    GroupBox2: TGroupBox;
    Label3: TLabel;
    ItemList: TComboBox;
    DatePicker: TJvDatePickerEdit;
    Label7: TLabel;
    edWeight: TJvValidateEdit;
    Label4: TLabel;
    procedure btnCancelClick(Sender: TObject);
    procedure edOverallEnter(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ItemListKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure btnOKClick(Sender: TObject);
  private
    { Private-Deklarationen }
    fPath: String;
    fItems: TStringList;
//  protected
    fWasteItem: TWasteItem;
  public
    { Public-Deklarationen }
    property Waste: TWasteItem read fWasteItem write fWasteItem;
  end;

var
  ItemDlg: TItemDlg;

implementation

{$R *.dfm}

procedure TItemDlg.btnCancelClick(Sender: TObject);
begin
  ModalResult := mrCancel;
end;

procedure TItemDlg.FormCreate(Sender: TObject);
begin
  fPath := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
  fItems := TStringList.Create;
  fWasteItem := TWasteItem.Create(Self);         <================ Das Objekt wird nie freigegeben, das es überschrieben wird (mit deinem Wast)
  If FileExists(fPath + 'waste.itm') then
  begin
    ItemList.Items.LoadFromFile(fPath + 'waste.itm');
  end;
end;

procedure TItemDlg.FormDestroy(Sender: TObject);
begin
  ItemList.Items.SaveToFile(fPath + 'waste.itm');
  fWasteItem.Free;                             <=============== hier gibst du das übergebene Objekt frei !
  fItems.Free;
end;

procedure TItemDlg.btnOKClick(Sender: TObject);
begin
  fWasteItem.WasteType := ItemList.SelText;
  fWasteItem.Weight := edWeight.Value;
  fWasteItem.TransportCost := edTrans.Value;
  fWasteItem.DisposalCost := edDisp.Value;
  fWasteItem.Date := DatePicker.Date;
  ModalResult := mrOK;
end;

end.
Ich habe mir mal erlaubt die unrelevanten Teile (StringListe in eine Combobox laden&speichen) zu entfernen.


Gruber_Hans_12345 15. Okt 2004 18:41

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
..... so wie ich das sehe, einfach die Create UND Destory weg, da du das Objekt ja von "aussen" befüllst !

phlux 15. Okt 2004 18:43

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
Ahh :shock: alles klar dann muss ich einfach nur gucken im OnCreate und OnDestroy Event ob die Property Waste nil ist oder nicht und dementsprechend handeln, ich probier das mal so. Danke schon mal im vorraus :)

mfg phlux :hi:

Keldorn 15. Okt 2004 18:47

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
Delphi-Quellcode:
property Waste: TWasteItem read fWasteItem write fWasteItem;
...
procedure TItemDlg.FormCreate(Sender: TObject);
begin
  fPath := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
  fItems := TStringList.Create;
  fWasteItem := TWasteItem.Create(Self); <<<<---
  If FileExists(fPath + 'waste.itm') then
  begin
    ItemList.Items.LoadFromFile(fPath + 'waste.itm');
  end;
end;
...
procedure TItemDlg.FormDestroy(Sender: TObject);
begin
  ItemList.Items.SaveToFile(fPath + 'waste.itm');
  fWasteItem.Free; <<<---
  fItems.Free;
end;

...
procedure TMainForm.btnDBEditClick(Sender: TObject);
var
  wItem: TWasteItem;

begin
  wItem := TWasteItem.Create(Self);
  try
    ShowItemDlg(wItem);
  finally
//    wItem.Free;
  end;
end;
So kannst du das nicht machen. Du erzeugst in deiner Form ein Wasteitem. mit
Delphi-Quellcode:
ItemDlg.Waste := Item;
kopierts du nichts sondern "biegst" den Zeiger um. Fwasteitem zeigt jetzt auf das übergebene Item. Das ursprünglich erstellte fwasteitem ist dein Speicherleck, da du das nicht wieder freigeben kannst. Da du im destructor der Form fwasteitem freigibst, Fwasteitem und item aber durch die := -Zuweisung das gleiche objekt ist, siehts du eine exception beim erneuten Aufruf von free.

Keine Ahnung, für was du das brauchst, wenn es häufig vorkomt, das du ein item übergeben mußt:
Delphi-Quellcode:
property Waste: TWasteItem read fWasteItem write fWasteItem;
verwende statt write write fwasteitem ein set-methode und verwende dort assign statt :=. Wenn du über eine >pro Version verfügst, gugg dir mal den Quelltext von einer Listbox an, und schau dir an, wie borland mit den Lines-eigenschaften umgeht.

Mfg Frank

Gruber_Hans_12345 15. Okt 2004 18:47

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
naja, im OnCreate wirds immer nil sein, da sie ja zu dieser zeit noch nicht initialisiert wurde (von deiner ItemDlg.Waste := Item;)

phlux 15. Okt 2004 18:47

Re: Speicherleck oder nicht bzw. wer findet den Fehler?
 
Hab es jetzt so umgeändert:

Delphi-Quellcode:
procedure TMainForm.btnDBEditClick(Sender: TObject);
var
  wItem: TWasteItem;

begin
  wItem := TWasteItem.Create(Self);
  ShowItemDlg(wItem);
end;

procedure TItemDlg.FormCreate(Sender: TObject);
begin
  fPath := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
  fItems := TStringList.Create;
  //fWasteItem wird nur noch erstellt wenn an Waste kein Objekt vom Typ
  //TWasteItem übergeben wird
  if Waste = nil then
    fWasteItem := TWasteItem.Create(Self);
  If FileExists(fPath + 'waste.itm') then
  begin
    ItemList.Items.LoadFromFile(fPath + 'waste.itm');
  end;
end;
Den OnDestroy Event hab ich unangetastet gelassen da man ja so oder so das WasteItem übergibt und es dann frei gibt, ich habs also - so wie ich es verstanden hab - doppelt freigegeben.

mfg phlux

Edit: Stimmt, pack ich das ganze nach OnShow dann dürfte es stimmen :wall:


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