Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   FreePascal Speicher Freigeben (https://www.delphipraxis.net/163458-speicher-freigeben.html)

stiftII 29. Sep 2011 12:45

Speicher Freigeben
 
Hallo,

ich habe folgende Funktion:
Delphi-Quellcode:
function ExtraColumsStringsDB(firma:string):TStringlist;
var
  Temp: Array Of TColumn;
  i: integer;
begin
     Result := TStringList.Create;
     Temp := GetExtraFields(firma);
     for i:=0 to high(Temp) do
     begin
       result.Add(Temp[i].FieldName );
     end;
end;
Aufgerufen wird diese zB so:
Delphi-Quellcode:
ExtraColumsStringsDB('name').count
Allerdings ist mir aufgefallen, dass bei dieser Vorgehensweise der verwendete Speicher der Funktion niemals freigegeben werden kann. (FPC hat ja keinen Garbage Collector)

Wenn man den Speicher in der Funktion freigeben würde, könnte man den Rückgabewert (TStringlist) ja niemals benutzen.

Gibt es irgendeine Möglichkeit diese nicht mehr verwendeten Variablen nach Ausführung der Funktion wieder freizugeben ?

Grüße
stiftII

Luckie 29. Sep 2011 12:48

AW: Speicher Freigeben
 
So was löst man in der Regel, in dem der Aufrufer das Objekt zur Verfügung stellt und es der Routine übergibt.

Alaitoc 29. Sep 2011 12:50

AW: Speicher Freigeben
 
Mach es doch so, dass eine StringList der Methode übergeben werden muss.
Dann noch überprüfen ob die überhaupt existiert, sie vll. clearen und mit Werten füllen.

MfG Alaitoc

Edith sagt: "Luckie war schneller".

Bernhard Geyer 29. Sep 2011 12:50

AW: Speicher Freigeben
 
oder den Funktionsnamen so wählen das klar ist das der Aufrufer aufräumen muss. z.B. CreateExtraColumsStrings

angos 29. Sep 2011 12:51

AW: Speicher Freigeben
 
Hi,

ich würde das Ganze ein wenig anders angehen (auch wenn schon Antworten da sind, hier die mögliche Lösung):


Delphi-Quellcode:
function ExtraColumsStringsDB(firma:string; const ASL: TStringlist): Boolean;
var
  Temp: Array Of TColumn;
  i: integer;
begin
  try
    Result := True;

    Temp := GetExtraFields(firma);
    for i:=0 to high(Temp) do
    begin
      ASL.Add(Temp[i].FieldName );
    end;
  except
    Result := False;
  end;
end;

procedure dosomething;
var
  SL:TStringList;
begin
  SL := TStringList.Create;
  try
    ExtraColumsStringsDB('EINEFIRMA', SL);
  finally
    SL.Free;
  end;
end;

DeddyH 29. Sep 2011 12:53

AW: Speicher Freigeben
 
Die Liste als Parameter zu übergeben ist trotzdem die bessere Option, da sonst bei mehrfachem Aufruf der Funktion auch mehrere Instanzen erzeugt werden. Wenn man dann nicht jede in einer Variablen speichert und freigibt hat man die schönsten Speicherlecks produziert.

p80286 29. Sep 2011 13:40

AW: Speicher Freigeben
 
Zitat:

Zitat von DeddyH (Beitrag 1127467)
Wenn man dann nicht jede in einer Variablen speichert und freigibt hat man die schönsten Speicherlecks produziert.

Das würde ich als selbsverständlich vorraussetzen.

Gruß
K-H

Luckie 29. Sep 2011 13:49

AW: Speicher Freigeben
 
Zitat:

Zitat von angos (Beitrag 1127466)
ich würde das Ganze ein wenig anders angehen (auch wenn schon Antworten da sind, hier die mögliche Lösung):

Und wo ist das jetzt anders, als zu den bisherigen Vorschlägen: Aufrufer erzeugt Objekt und übergibt es als Parameter an die Routine.

DeddyH 29. Sep 2011 14:00

AW: Speicher Freigeben
 
Zitat:

Zitat von p80286 (Beitrag 1127484)
Zitat:

Zitat von DeddyH (Beitrag 1127467)
Wenn man dann nicht jede in einer Variablen speichert und freigibt hat man die schönsten Speicherlecks produziert.

Das würde ich als selbsverständlich vorraussetzen.

Gruß
K-H

Negativbeispiel: http://www.delphipraxis.net/1099023-post9.html (Handler.GetAllDataSets liefert eine Stringliste)

r2c2 29. Sep 2011 19:21

AW: Speicher Freigeben
 
Und wenn man den Parameter noch als TStrings (statt TStringList) deklariert, kann man sogar so Spielchen machen wie Memo.Lines übergeben...

mfg

Christian

stiftII 30. Sep 2011 01:41

AW: Speicher Freigeben
 
Vielen Dank :) .. werde es dann so machen, dass ich eine temp Variable mit übergebe und aus der Funktion mache ich dann eine Prozedur.

Dachte es gäbe vllt, wie bei Java eine Möglichkeit nicht benötigte Resourcen zu identifizieren und freizugeben.

stiftII

Sir Rufo 30. Sep 2011 03:18

AW: Speicher Freigeben
 
Zitat:

Zitat von stiftII (Beitrag 1127589)
Vielen Dank :) .. werde es dann so machen, dass ich eine temp Variable mit übergebe und aus der Funktion mache ich dann eine Prozedur.

Dachte es gäbe vllt, wie bei Java eine Möglichkeit nicht benötigte Resourcen zu identifizieren und freizugeben.

stiftII

Gibt es schon, wenn du dir eine Stringliste als Interface baust. :stupid:

stiftII 30. Sep 2011 13:20

AW: Speicher Freigeben
 
Zitat:

Zitat von Sir Rufo (Beitrag 1127591)
Zitat:

Zitat von stiftII (Beitrag 1127589)
Vielen Dank :) .. werde es dann so machen, dass ich eine temp Variable mit übergebe und aus der Funktion mache ich dann eine Prozedur.

Dachte es gäbe vllt, wie bei Java eine Möglichkeit nicht benötigte Resourcen zu identifizieren und freizugeben.

stiftII

Gibt es schon, wenn du dir eine Stringliste als Interface baust. :stupid:

:stupid: Macht das sinn xD?

stiftII 30. Sep 2011 14:11

AW: Speicher Freigeben
 
Kurze Frage nochmal hierzu.

Warum funktioniert das so nicht ("function ExtraColumsStringsDB" erstellt die Stringlist) ?

Delphi-Quellcode:
function ExtraColumsStringsDB(firma:string; ASL: TStringlist): Boolean;
var
  Temp: Array Of TColumn;
  i: integer;
begin
  try
    Result := True;
    SL := TStringList.Create;
    Temp := GetExtraFields(firma);
    for i:=0 to high(Temp) do
    begin
      ASL.Add(Temp[i].FieldName );
    end;
  except
    Result := False;
  end;
end;

procedure dosomething;
var
  SL:TStringList;
begin
  try
    ExtraColumsStringsDB('EINEFIRMA', SL);
  finally
    SL.Free;
  end;
end;

DeddyH 30. Sep 2011 14:14

AW: Speicher Freigeben
 
Weil der Stringlisten-Parameter const deklariert ist? Aber das ist die merkwürdigste Variante, die ich hier bislang gesehen habe, ist das nur zum Herumprobieren, oder willst Du das tatsächlich produktiv so einsetzen?

stiftII 30. Sep 2011 14:20

AW: Speicher Freigeben
 
Zitat:

Zitat von DeddyH (Beitrag 1127758)
Weil der Stringlisten-Parameter const deklariert ist? Aber das ist die merkwürdigste Variante, die ich hier bislang gesehen habe, ist das nur zum Herumprobieren, oder willst Du das tatsächlich produktiv so einsetzen?

Ups, der ist nicht konstant, ich hatte nur das Beispiel von angos kopiert/editiert. Hab das mal rauseditiert.

Ja, ich würde das gerne "produktiv einsetzen" ;). Meine Funktion/Prozedur sieht so aus:

Delphi-Quellcode:
procedure ExtraColumnsStringsDB(firma:string; ColumnStrings:TStringlist);
var
  Temp: Array Of TColumn;
  i: integer;
begin
     Temp := GetExtraFields(firma);
     for i:=0 to high(Temp) do
     begin
       ColumnStrings.Add(Temp[i].FieldName );
     end;
     //Free all columns
     for i:=0 to high(Temp) do
     begin
       Temp[i].Free;
     end;
end;
Das geht so auch, mich würde nur interessieren, warum die andere Variante nicht funktioniert (Access Violation).

Grüße
stiftII

DeddyH 30. Sep 2011 14:24

AW: Speicher Freigeben
 
Rein akademisch: ich denke, wenn Du es so machen willst, musst Du SL als Var-Parameter übergeben.

p80286 30. Sep 2011 14:55

AW: Speicher Freigeben
 
Zitat:

Zitat von stiftII (Beitrag 1127755)
Delphi-Quellcode:
function ExtraColumsStringsDB(firma:string; ASL: TStringlist): Boolean;
var
  Temp: Array Of TColumn;
  i: integer;
begin
  try
    Result := True;
    SL := TStringList.Create;      {--- und wofür wird SL genutzt?}
    Temp := GetExtraFields(firma);
    for i:=0 to high(Temp) do
    begin
      ASL.Add(Temp[i].FieldName );
    end;
  except
    Result := False;
  end;
end;

procedure dosomething;
var
  SL:TStringList;
begin
  { hier fehlt ein SL:=tstringlist.Create!!!!!!}
  try
    ExtraColumsStringsDB('EINEFIRMA', SL);
  finally
    SL.Free;
  end;
end;

Gruß
K-H

stiftII 30. Sep 2011 15:04

AW: Speicher Freigeben
 
Da fehlt nen A in der Funktion. Hatte die nur so kopiert :x

Jetzt aber:

Delphi-Quellcode:
function ExtraColumsStringsDB(firma:string; ASL: TStringlist): Boolean;
var
  Temp: Array Of TColumn;
  i: integer;
begin
  try
    Result := True;
    ASL := TStringList.Create;
    Temp := GetExtraFields(firma);
    for i:=0 to high(Temp) do
    begin
      ASL.Add(Temp[i].FieldName );
    end;
  except
    Result := False;
  end;
end;

procedure dosomething;
var
  SL:TStringList;
begin
  try
    ExtraColumsStringsDB('EINEFIRMA', SL);
  finally
    SL.Free;
  end;
end;

himitsu 30. Sep 2011 15:23

AW: Speicher Freigeben
 
Zitat:

Zitat von DeddyH (Beitrag 1127761)
Rein akademisch: ich denke, wenn Du es so machen willst, musst Du SL als Var-Parameter übergeben.

Da er nichtmal prüft, ob vorher nicht schon eine Stringliste in dem Parameter übergeben wurde,
sollte er es sogar mit OUT, anstatt VAR deklarieren,
damit man gleich weiß was auf einen zukommt, wenn man diesen Funktionsheader sieht.

DeddyH 30. Sep 2011 16:33

AW: Speicher Freigeben
 
Das stimmt zwar, aber ich halte die gezeigte Vorgehensweise sowieso zumindest für problematisch. Schaut man sich dosomething alleine an, dann ist man doch erst einmal verwirrt.

p80286 30. Sep 2011 17:14

AW: Speicher Freigeben
 
Das würde ich unter tricky noch akzeptieren, ich käme hier ins Grübeln:
Delphi-Quellcode:
function ExtraColumsStringsDB(firma:string; ASL: TStringlist): Boolean;
......
    ASL := TStringList.Create;
das mag zwar gehen, aber wenn man mal die Übersicht verliert...

Gruß
K-H

DeddyH 30. Sep 2011 17:25

AW: Speicher Freigeben
 
Naja, eine lokale Instanzvariable, die nirgends erzeugt, aber dann freigegeben wird... Da würde ich zunächst mit einer AV rechnen.

Luckie 30. Sep 2011 17:48

AW: Speicher Freigeben
 
na ja, übersichtlich ist anders. Wenn man konsequent den Spiecher auch da wieder frei gibt, wo er reserviert wird, dann läuft man auch nicht in Gefahr den Überblick zu verlieren.

DeddyH 30. Sep 2011 18:01

AW: Speicher Freigeben
 
Japp. Aus dem Bauch heraus würde ich es ungefähr so machen:
Delphi-Quellcode:
function ExtraColumsStringsDB(const firma: string; ASL: TStrings): Boolean;
var
  Temp: Array Of TColumn;
  i: integer;
begin
  Result := False;
  Assert(Assigned(ASL));
  try
    ASL.Clear;
    //das sieht mir komisch aus, ist das auch so ein Kandidat?
    Temp := GetExtraFields(firma);
    for i:=0 to high(Temp) do
    begin
      ASL.Add(Temp[i].FieldName );
    end;
    Result := True;
  except
    on E: Execption do
      //irgendwie reagieren
  end;
end;

procedure dosomething;
var
  SL: TStringList;
begin
  SL := TStringlist.Create;
  try
    ExtraColumsStringsDB('EINEFIRMA', SL);
    //noch irgendetwas mit SL anstellen
  finally
    SL.Free;
  end;
end;

r2c2 30. Sep 2011 19:03

AW: Speicher Freigeben
 
Gibt es irgend einen Grund für das try..except in ExtraColumsStringsDB? Wenn mand ie Exception nicht behandeln kann, dann sollte die auch nicht behandelt werden und erst in einer höheren Schicht taucht dann das try..except auf. Dann kann man sich auch den überflüssigen Boolean-Rückgabewert sparen.

mfg

Christian

himitsu 30. Sep 2011 19:13

AW: Speicher Freigeben
 
Zitat:

Delphi-Quellcode:
//das sieht mir komisch aus, ist das auch so ein Kandidat?

Da sich hier Delphi um die Initialisierung und Feigabe des Arrays kümmert, ist das nicht wirklich problematisch.

Interfaces, dynamische Arrays und Strings kann man daher ganz gut als Result verwenden.


Einfache Typen, Records, statische Arrays und natürlich eine Kombination aus all Diesen sind natürlich auch möglich.

DeddyH 1. Okt 2011 10:34

AW: Speicher Freigeben
 
Da die Elemente aber anscheinend eine Eigenschaft Fieldname haben, wird es sich wohl um Records oder Objekte handeln. Und Objekte werden in dem Code ja nicht freigegeben, daher meine Frage.

himitsu 1. Okt 2011 13:40

AW: Speicher Freigeben
 
Von Objekten hab ich auch nichts gesagt :mrgreen:

Records in Arrays wären aber OK :)


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