![]() |
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; |
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. |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
Delphi-Quellcode:
Nicht empfohlene Lösung:
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;
Delphi-Quellcode:
Bis bald...
uses
mormot.core.data; var sl: TStringList; begin with TAutoFree.One(sl, CreateAndFillStringList) do ShowMessage(sl.Text); end; Thomas |
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. |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
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. |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
* Ja, die Vairable selbst wird nicht geändert, * aber der Inhalt schon. Zitat:
Delphi-Quellcode:
Was erstellt wird, muß auch wieder freigegeben werden, denn das "Objekt" macht es nicht von selbst.
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; ODER
Delphi-Quellcode:
* hier wird Extern nicht freigegeben
// 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; * 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 ... |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
ABER: Mann sollte die Benamsung "Create...." nennen, damit man weiß, dass ein Objekte erzeugt wird, was extern freigegeben werden muß! :warn: |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
Delphi-Quellcode:
funktioniert prima.
sl := FunctionDieEineStringlistErzeugt(bla, blub);
try Verarbeite(sl); finally sl.Free; end; Problematisch ist eher die erzeugende Function selbst, denn was, wenn nach dem Erzeugen der Stringlist eine Exception ausgelöst wird?
Delphi-Quellcode:
Und schwupps hat man ein Leak. Natürlich ist das nie so offensichtlich wie in diesem Beispiel.
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
begin Result := TStringList.Create; Result.Add(bla); Result.Add(blub); raise Exception.Create('Test'); end; Meine Lösung dafür sieht so aus:
Delphi-Quellcode:
Ich bin mir allerdings sicher, dass das irgendwie eleganter gehen müsste.
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; Edit: Mir ist gerade noch eine Alternative eingefallen:
Delphi-Quellcode:
Ist aber auch nicht wirklich elegant.
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; |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
wenn dann sl auf nil gesetz wird, ist dann nicht auch result == nil? Grüße Klaus |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
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:
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.
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; |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Darum verwende ich z.B. statt einer StringList (Rückgabetyp besser TStrings) immer öfters Arrays.
Sowohl mit TStrings/TStringList, als auch mit dem String-Array, lassen sich viele gleiche Dinge tun, aber Variante mit den Objekten hat eben auch Nachteile.
Delphi-Quellcode:
for var S in getSL do // egal ob StringArray oder StringList (nur am Speicherleck ist man dann selber Schuld)
ShowMessage(S); SL.Clear; SL.AddStrings(getSL); Memo.Lines.AddStrings(getSL); A := SL.ToStringArray; ... Interfaces .... Ja, es gibt von Microsoft ein IStrings, aber das ist mit unserem TStrings nicht kompatibel, mit IStringsAdapter macht es keinen Spaß und von IXPStrings wollen wir garnicht erst reden. |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
moin in die runde,
erstmal, cool, so viele antworten, tks.. und - ohne jetzt auf die einzelnen punkte naeher einzugehen - so wirklich schlauer bin ich jetzt zwar auch nicht, aber es handelt sich hier um uralte funktionen, die ich mittlerweile ganz anders loese. es hat mich halt einfach mal interessiert.. und dass man keine objekte zurueckgeben soll, hmmm.. - naja, ich mach das sehr gerne. auch habe ich ne menge stringlisten, denen ich objekte anhaenge, weil man dann auf diese so schoen mit dem namen zugreifen kann. ich faends halt super, wenn es ein "modul" oder irgendwas gaebe, in welchem man ganz genau sehen koennte, "welche variable wurde wo nicht freigegeben".. wuensch euch was.. ..de Schorsch |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
ABER von Vorteil wäre es, wenn man dem Funktionsnamen dieses Verhalten ansieht.
Delphi-Quellcode:
//var FSL: TStringList;
function GetSL: TStrings; begin Result := FSL; Result.Clear; Result.Add('blub'); end; SL := GetSL; ... function CreateSL: TStrings; // MakeSL oder sowas begin Result := TStringList.Create; Result.Add('blub'); end; SL := CreateSL; ... SL.Free; // bezüglich Fehlerbehandlung Try-Except/Finally siehe oben
Delphi-Quellcode:
procedure GetSL(SL: TStrings);
begin SL.Clear; // ohne Clear, wenn man optional anhängen können möchte (außerhalb Clear oder nicht) SL.Add('blub'); end; |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
[Hier stand Blödsinn oder nicht genau das was gesucht wurde]
|
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Moin...8-)
Zitat:
![]() |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Danke, werde ich mir mal angucken.
uebrigens wegen der benamsung: das war doch nur fuer euch als beispiel. natuerlich heissen meine funktionen "get, set, create, MachDiesUndMachDas" ;-) ..de Schorsch |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:59 Uhr. |
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-2025 by Thomas Breitkreuz