Autor Beitrag
DeadlyAppearance
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 15:19 
Hallo zusammen.
Und zwar habe ich das Problem, dass mein Programm immer mehr Speicher belegt und nicht mehr frei gibt.
Ich habe nun den Problembereich gefunden und soweit vereinfacht, dass ich es hier mal posten kann.
Wie es scheint, liegt das Problem bei MySation.MyItemList := TObjectList.Create;.

Was das ganze machen soll?
Es gibt eine List mit "Stationen", welche aus einem Station-Objekt besteht, welches wieder eine List an Item-Objekten beinhaltet.
Rein von der Funktionalität funktioniert es tadenlos, nur beim Freigeben des Speichers scheint etwas schief zu laufen.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
  TMyStation = class(TObject)
    StationName : Integer;
    MyItemList: TObjectList;
  end;

  TMyItem = class(TObject)
    StationName, ItemName, ItemJump : Integer;
    ItemPrice : Double;
  end;


procedure TForm1.Button2Click(Sender: TObject);
var
  MyList : TObjectList;
  MySation : TMyStation;
  MyItem : TMyItem;
  i : Integer;
begin
  MyList := TObjectList.Create;

  MyItem := TMyItem.Create;
  try
    MyItem.ItemName := 12;
    MyItem.ItemPrice := 10.12;
  except
    FreeAndNil(MyItem);
  end;

  try
    for I := 0 to 999 do
    begin
      MySation := TMyStation.Create;
      MySation.MyItemList := TObjectList.Create;
      MySation.StationName := 1234;
      MySation.MyItemList.Add(MyItem);
      MyList.Add(MySation);
    end;
  finally
    FreeAndNil(MyList);
  end;
end;


Ich hoffe ihr könnt mir weiter helfen, da ich schon seit einigen Stunden am rumdocktern bin und das Problem nicht finden kann.

Danke

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Do 18.12.08 15:23 
Du gibst am Ende nur die Liste frei, nicht aber die einzelnen Items, die sich darin befinden

AXMD
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 18.12.08 15:34 
Das sollte eigentlich auch nicht nötig sein, denn OwnsObjects ist standardmäßig ohne Angabe im Konstruktor ja True.
Aber du könntest Clear vorher aufrufen, vielleicht ändert das etwas.

In der Delphi Doku hört es sich so an als würden die Objekte auch freigegeben, wenn die Liste zerstört wird, in der FreePascal Doku hört es sich nur so an, wenn die Objekte entfernt oder Clear aufgerufen wird.

Ich werde mal schauen was genau dabei passiert.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 15:35 
Ahh, k.
Ich dachte, dies passiert automatisch beim Freigeben des übergeordneten Objektes.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
  TMyStation = class(TObject)
    StationName : Integer;
    MyItemList: TObjectList;
    destructor Destroy; override;
  end;

destructor TMyStation.Destroy;
begin
  MyItemList.Free;
  inherited Destroy;
end;


Bei dieser Lösung kommt eine "Ungültige Zeigeroperation" Fehlermeldung.
Wie mache ich das richtig?

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 18.12.08 15:38 
Wo wird MyItemList denn erzeugt? Normalerweise ja im Constructor. Und ja, TObjectList gibt seine enthaltenen Objekte automatisch frei, wenn OwnsObjects nicht explizit auf false gesetzt wurde.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 15:43 
Vorher habe ich MyItemList im der Schleife nach dem Create von MySation aufgerufen.
Jetzt habe ich es mal in den constructor gepackt.

Aber leider frisst das Programm auch weiterhin bei jedem Buttonclick immer mehr kB.
Also gibt er die Liste nicht korrekt frei.

Da es sich ja nur um ein kurzen Quelltext handelt, könnt ihr diesen ja gerne mal bei euch kurz einbinden, vielleicht sehr ihr dann wo genau das Problem liegt.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 18.12.08 15:49 
Ich habe mir jetzt deinen Code angeschaut und konnte das Problem nicht reproduzieren. :nixweiss:
Es wächst nur die Speicherbelegung im Taskmanager und das liegt am Speichermanager von Delphi.

Alle Objekte werden wieder freigegeben bis auf eines:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  MyItem := TMyItem.Create;
  try
    MyItem.ItemName := 12;
    MyItem.ItemPrice := 10.12;
  except
    FreeAndNil(MyItem);
  end;
Und dass das nicht freigegeben wird ist ja klar, weil du es nur in except freigibst und nicht immer.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 15:51 
MyItem kann ich ja nicht freigeben, da es ja an meinem Stationobjekt hängt.
Aber durch das zerstören des Stationobjektes sollte ja auch das Item rausfliegen.

Und bezüglich Taskmanager, wenn ich das Programm in einer weit größeren Schleife laufen lasse bin ich irgend wann bei
100MB und mehr, also scheint das ja doch nen Problem mitm freigeben zu sein.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Do 18.12.08 15:53 
user profile iconDeadlyAppearance hat folgendes geschrieben Zum zitierten Posting springen:
MyItem kann ich ja nicht freigeben, da es ja an meinem Stationobjekt hängt.
Aber durch das zerstören des Stationobjektes sollte ja auch das Item rausfliegen.


Eben deshalb habe ich ja vorhin geschrieben, dass du jedes Item der Liste getrennt freigeben solltest. Ist doch zumindest einen Versuch wert, oder nicht ;)?

AXMD
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 15:56 
Das war ja mein Versuch wie oben gezeigt im destructor, doch leider funktioniert dieser nicht.
Deshalb die bitte, wie mache ich das?

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 18.12.08 15:56 
user profile iconDeadlyAppearance hat folgendes geschrieben Zum zitierten Posting springen:
MyItem kann ich ja nicht freigeben, da es ja an meinem Stationobjekt hängt.
Aber durch das zerstören des Stationobjektes sollte ja auch das Item rausfliegen.
Aaaah, jetzt verstehe ich, das hab ich übersehen...
Nein, dadurch fliegt es nicht heraus, das musst du im Destruktor machen, ich schaue mir das nochmal an, auch deinen Code dazu.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 16:00 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconDeadlyAppearance hat folgendes geschrieben Zum zitierten Posting springen:
MyItem kann ich ja nicht freigeben, da es ja an meinem Stationobjekt hängt.
Aber durch das zerstören des Stationobjektes sollte ja auch das Item rausfliegen.
Aaaah, jetzt verstehe ich, das hab ich übersehen...
Nein, dadurch fliegt es nicht heraus, das musst du im Destruktor machen, ich schaue mir das nochmal an, auch deinen Code dazu.


Oha, danke dir.
Nun sind wir schon mal nen Schritt weiter :)
Mein Beispiel oben mit dem destructor funktioniert leider nicht.
Bin sehr gespannt, wie man das nun korrekt macht.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 18.12.08 16:13 
user profile iconDeadlyAppearance hat folgendes geschrieben Zum zitierten Posting springen:
Mein Beispiel oben mit dem destructor funktioniert leider nicht.
Doch, und genau das ist das Problem ;-).
Du fügst das selbe Item in mehrere ObjectLists ein, und beim ersten freigegebenen TMyStation Objekt wird es im Destruktor wie du ihn jetzt hattest freigegeben. Davon wissen die anderen ObjectLists aber nix. ;-)

Wenn du für jedes Einfügen in die Liste ein neues Objekt erzeugst, dann funktioniert das auch.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
  try
    for I := 0 to 999 do
    begin
      MySation := TMyStation.Create;
      MySation.MyItemList := TObjectList.Create;
      MySation.StationName := I;
      MyItem := TMyItem.Create;
      try
        MyItem.ItemName := 12;
        MyItem.ItemPrice := 10.12;
        MySation.MyItemList.Add(MyItem);
      except
        FreeAndNil(MyItem);
      end;
      MyList.Add(MySation);
    end;
  finally
    FreeAndNil(MyList);
  end;
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 16:31 
Also mit der Fehlermeldung lag daran wie du gesagt hast.
War mein Fehler in dem Umbauen fürs Beispiel.

Aber...
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
  TMyStation = class(TObject)
    StationName : Integer;
    MyItemList: TObjectList;
    constructor Create;
    destructor Destroy; override;
  end;

  TMyItem = class(TObject)
    StationName, ItemName, ItemJump : Integer;
    ItemPrice : Double;
  end;

{ TMyStation }

constructor TMyStation.Create;
begin
  MyItemList := TObjectList.Create;
end;

destructor TMyStation.Destroy;
begin
  MyItemList.Free;
  inherited Destroy;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  MyList : TObjectList;
  MySation : TMyStation;
  MyItem : TMyItem;
  i : Integer;
begin
  MyList := TObjectList.Create;

  try
    for I := 0 to 999 do
    begin
      MySation := TMyStation.Create;
      MySation.MyItemList := TObjectList.Create;
      MySation.StationName := I;
      MyItem := TMyItem.Create;
      try
        MyItem.ItemName := 12;
        MyItem.ItemPrice := 10.12;
        MySation.MyItemList.Add(MyItem);
      except
        FreeAndNil(MyItem);
      end;
      MyList.Add(MySation);
    end;
  finally
    FreeAndNil(MyList);
  end;
end;

...es frisst sich immer noch voll :(.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 18.12.08 16:38 
Du erzeugst die ObjectList ja auch doppelt ;-), einmal im Konstruktor und einmal in der Zeile danach.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 16:42 
Hrhr, danke, nun gehts.

Aber warum muss ich nun in desctructor die MyItemList frei geben?
Warum wird diese nicht mit zerstört, wenn ich das Objekt lösche, an dem diese hängt?

Möchte das gerne für die Zukunft verstehen :)

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19341
Erhaltene Danke: 1752

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 18.12.08 16:50 
user profile iconDeadlyAppearance hat folgendes geschrieben Zum zitierten Posting springen:
Warum wird diese nicht mit zerstört, wenn ich das Objekt lösche, an dem diese hängt?
Bei einer ObjectList passiert das ja nur, weil diese im Destruktor (in TList) Clear aufruft und daraufhin die Objekte aus der Liste entfernt und gelöscht werden. Die Klasse, die du benutzt, weiß also, dass es eine Liste von Objekten gibt und diese ggf. entfernt werden müssen.

Deine eigenen Objekte sind aber von TObject abgeleitet. Dieses kann ja nicht wissen was du für eigene Sachen in dein Objekt steckst, und dementsprechend kann dieser existierende Destruktor dir nicht die Arbeit abnehmen.

Die Programmierer der TList und TObjectList haben genau dieses Freigeben auch im Konstruktor selbst programmiert. Und als Programmierer deiner Klasse TMyStation musst du das auch tun. ;-)
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 18.12.08 16:56 
Und das doppelte Instanziieren könnte nicht passieren, wenn man die ObjectList als ReadOnly-Property definiert.
DeadlyAppearance Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 113

Win 7
Delphi 2010 Arch., C# VS 2008
BeitragVerfasst: Do 18.12.08 17:16 
Ja dann mal vielen Dank in die Runde für die schnelle Hilfe.
Wünsche euch noch einen schönen Abend.

_________________
Als du auf die Welt kamst, weintest du, und um dich herum freuten sich alle. Lebe so, daß, wenn du die Welt verläßt, alle weinen und du allein lächelst.