Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   noch was zu: "Nach 20/30 starts aus der IDE speicher voll" (https://www.delphipraxis.net/213901-noch-zu-nach-20-30-starts-aus-der-ide-speicher-voll.html)

schorsch666 16. Okt 2023 20:55

noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Moin @ALL,
hatte jetzt nochmal bissi zeit... und functions gefunden, die ne stringlist zurueckgeben. und laut test (siehe code) werden die auch nicht freigegeben (sagt jedenfalls "ReportMemoryLeaksOnShutdown") und ist ja auch irgendwie logisch.

kann man sowas ueberhaupt irgendwie freigeben?? werde jetzt jedenfalls alles mal auf variante 2 umstellen. vllt. hat ja jemand nen kommentar uebrig...

LG..

..de Schorsch


Delphi-Quellcode:

    function getSL: TStringList; overload;
    function getSL(var SL: TStringList): Boolean; overload;

procedure TForm1.Button1Click(Sender: TObject);
begin
  showmessage(getSL.Text);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  var sl := TStringList.Create;
  try
    getSL(sl);
    showmessage(sl.Text);
  finally
    FreeAndNil(sl);
  end;
end;

function TForm1.getSL: TStringList;
begin
  result := TStringList.Create;

  result.Add('haha');
  result.Add('hehe');
  result.Add('hihi');
  result.Add('hoho');
  result.Add('huhu');
end;

function TForm1.getSL(var SL: TStringList): Boolean;
begin
  SL.Add('haha');
  SL.Add('hehe');
  SL.Add('hihi');
  SL.Add('hoho');
  SL.Add('huhu');
end;

jaenicke 16. Okt 2023 21:45

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Du solltest aus dem var beim Parameter ein const machen, denn die Funktion soll die Referenz auf die Stringliste ja nicht ändern, sondern die Liste lediglich nutzen (füllen).

Wenn du dich um die Freigabe nicht kümmern möchtest, musst du Interfaces nutzen. Die musst du aber natürlich dann auch erst implementieren. Dann ginge auch Variante 1.

mytbo 16. Okt 2023 22:18

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Zitat:

Zitat von schorsch666 (Beitrag 1528203)
vllt. hat ja jemand nen kommentar uebrig...

Variante 1, so:
Delphi-Quellcode:
function CreateAndFillStringList: TStringList;
begin
  Result := TStringList.Create;
  Result.Add('...');
end;

begin
  var sl: TStringList := CreateAndFillStringList;
  try
    sl.Add('more');
    ShowMessage(sl.Text);
  finally
    sl.Free;
  end;
Nicht empfohlene Lösung:
Delphi-Quellcode:
uses
  mormot.core.data;

var
  sl: TStringList;
begin
  with TAutoFree.One(sl, CreateAndFillStringList) do
    ShowMessage(sl.Text);
end;
Bis bald...
Thomas

Redeemer 16. Okt 2023 22:28

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Man gibt normalerweise mit Funktionen keine Objekte zurück, außer es sind die Getter eines anderen Objekts, das die Instanz des zurückgegebenen Objekts verwaltet (Beispiel: die diversen Lines von TMemo und Items von TComboBox). Oder irgendeine andere Klasse kümmert sich darum, dass die irgendwann freigegeben werden (z.B. TListItems.Add).
Nur Konstruktoren geben Objekte implizit zurück die nennt man auch so. Dann weiß man: Ich muss die so benutzen, wie du es bei Button2 gemacht hast. Im allergrößten Notfall macht man das wie mytbo geschrieben hat - aber auch hier heißt die Methode irgendwas mit "Create" und da weiß ich sofort, ich muss das Ding freigeben.

Wie jaenicke schon sagte, sind übergibt man Klassen auch normalerweise nicht als var, da das Argument eigentlich nur der Zeiger ist und man die Felder und Eigenschaften von Klassen immer schreiben kann. In Delphi werden Klassen weder als var noch als const übergeben. Macht man im Normalfall bei Dingen, die ein Zeiger oder kleiner sind.

Alternativ zu Interfaces kann man Records nutzen. Nachteil: Die haben keinen Destruktor, haben keine Vererbung und können sich nicht selbst referenzieren.

jaenicke 16. Okt 2023 23:16

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Zitat:

Zitat von Redeemer (Beitrag 1528206)
In Delphi werden Klassen weder als var noch als const übergeben. Macht man im Normalfall bei Dingen, die ein Zeiger oder kleiner sind.

Die Verwendung von const hat den Vorteil, dass man die Referenz nicht aus Versehen überschreiben kann. Ohne var hätte das zwar beim Aufrufer keinen Effekt, aber wenn jemand innerhalb der Methode als erstes die Stringliste neu anlegt, wäre in der übergebenen Liste hinterher nichts drin. Deshalb verwende ich const ganz gerne, auch wenn es an einer Stelle performancemäßig keinen Vorteil bringt.

Umgekehrt verwende ich es bei Interfaces teilweise nicht, wenn die Gefahr besteht, dass jemand als Parameter direkt einen Konstruktoraufruf verwendet, was mit der Referenzzählung Probleme machen kann.

himitsu 17. Okt 2023 00:36

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Zitat:

Zitat von jaenicke (Beitrag 1528204)
Du solltest aus dem var beim Parameter ein const machen, ...

Syntaktisch korrekt, aber ich würde dennoch empfehlen nicht CONS, sondern garnichts anzugeben.

* Ja, die Vairable selbst wird nicht geändert,
* aber der Inhalt schon.




Zitat:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  showmessage(getSL.Text);
end;

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  var Temp := getSL.Text;
  showmessage(Temp.Text);
  Temp.Fee;
end;

// aber eigentlich
begin
  var Temp := getSL.Text;
  try
    showmessage(Temp.Text);
  finally
    Temp.Fee;
  end;
end;
Was erstellt wird, muß auch wieder freigegeben werden, denn das "Objekt" macht es nicht von selbst.

ODER
Delphi-Quellcode:
// FSL als Variable/Feld in der übergeordneten Klasse, also hier die TForm1

function TForm1.getSL: TStringList;
begin
  if not Assigned(FSL) then
    FSL := TStringList.Create; // oder im OnCreate UND im OnDestroy sowieso das FSL.Free;
  FSL.Clear;
  FSL.Add('haha');
  FSL.Add('hehe');
  FSL.Add('hihi');
  FSL.Add('hoho');
  FSL.Add('huhu');
  Result := FSL;
end;
* hier wird Extern nicht freigegeben
* gleichzeitig, bzw. kurz nacheinander aufgerufen, muß man bedenken, dass das Result des vorherigen Aufrufs sich auch mit verändert (weil selbes Objekt)

ODER z.B. irgendwas mit einem Interface
ODER
Delphi-Quellcode:
function TForm1.getSL: TArray<string>;

ODER ...

haentschman 17. Okt 2023 06:23

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Zitat:

Man gibt normalerweise mit Funktionen keine Objekte zurück
...davon habe ich reichlich. :wink: Meistens Objekte die in einer Liste verschwinden und mit der Liste freigegeben werden.
ABER: Mann sollte die Benamsung "Create...." nennen, damit man weiß, dass ein Objekte erzeugt wird, was extern freigegeben werden muß! :warn:

dummzeuch 17. Okt 2023 08:11

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Zitat:

Zitat von Redeemer (Beitrag 1528206)
Man gibt normalerweise mit Funktionen keine Objekte zurück

Solange klar ist, dass der Aufrufer sie freigeben muss, warum nicht?

Delphi-Quellcode:
sl := FunctionDieEineStringlistErzeugt(bla, blub);
try
  Verarbeite(sl);
finally
  sl.Free;
end;
funktioniert prima.

Problematisch ist eher die erzeugende Function selbst, denn was, wenn nach dem Erzeugen der Stringlist eine Exception ausgelöst wird?

Delphi-Quellcode:
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
begin
  Result := TStringList.Create;
  Result.Add(bla);
  Result.Add(blub);
  raise Exception.Create('Test');
end;
Und schwupps hat man ein Leak. Natürlich ist das nie so offensichtlich wie in diesem Beispiel.

Meine Lösung dafür sieht so aus:

Delphi-Quellcode:
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
begin
  Result := TStringList.Create;
  try
    Result.Add(bla);
    Result.Add(blub);
    raise Exception.Create('Test');
  except
    Result.Free;
    raise;
  end;
end;
Ich bin mir allerdings sicher, dass das irgendwie eleganter gehen müsste.

Edit: Mir ist gerade noch eine Alternative eingefallen:

Delphi-Quellcode:
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    sl.Add(bla);
    sl.Add(blub);
    raise Exception.Create('Test');
    Result := sl;
    sl := nil;
  finally
    sl.Free;
  end;
end;
Ist aber auch nicht wirklich elegant.

Klaus01 17. Okt 2023 08:51

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Zitat:

Zitat von dummzeuch (Beitrag 1528216)

Edit: Mir ist gerade noch eine Alternative eingefallen:

Delphi-Quellcode:
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    sl.Add(bla);
    sl.Add(blub);
    raise Exception.Create('Test');
    Result := sl;
    sl := nil;
  finally
    sl.Free;
  end;
end;
Ist aber auch nicht wirklich elegant.

Zeigt da nicht result auf die gleiche Adresse wie sl,
wenn dann sl auf nil gesetz wird, ist dann nicht auch result == nil?

Grüße
Klaus

dummzeuch 17. Okt 2023 09:11

AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
 
Zitat:

Zitat von Klaus01 (Beitrag 1528219)
Zitat:

Zitat von dummzeuch (Beitrag 1528216)

Edit: Mir ist gerade noch eine Alternative eingefallen:

Delphi-Quellcode:
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    sl.Add(bla);
    sl.Add(blub);
    raise Exception.Create('Test');
    Result := sl;
    sl := nil;
  finally
    sl.Free;
  end;
end;
Ist aber auch nicht wirklich elegant.

Zeigt da nicht result auf die gleiche Adresse wie sl,
wenn dann sl auf nil gesetz wird, ist dann nicht auch result == nil?

Ja, aber nein:

Sowohl Result als auch sl sind Pointer auf das das Objekt. Wenn ich einen davon auf nil setze, hat das keinen Einfluss auf den anderen. Anders sähe das aus, wenn man sl nicht auf nil setzt:

Delphi-Quellcode:
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
var
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    sl.Add(bla);
    sl.Add(blub);
    raise Exception.Create('Test');
    Result := sl;
//    sl := nil;
  finally
    sl.Free;
  end;
end;
Dann würde Result nach dem sl.Free auf ein freigegebenes Objekt zeigen und ein Zugriff hätte böse Folgen. Im Besten Fall eine Access Violation, im schlechtesten Fall würde zufälliger Code ausgeführt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz