Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe (https://www.delphipraxis.net/171251-problem-mit-speicherfreigabe-bei-dynamischen-array-als-function-uebergabe.html)

Helmi 28. Okt 2012 15:02

Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe
 
Hallo,

wie in diesem Thread nachzulesen ist, versuch ich über GetAdaptersInfo und GetAdaptersAddress Infos zu den Netzwerkverbindungen auszulesen.

Das klappt auch soweit ganz gut.

Ich hab das in einem Testprojekt getestet und hab jetzt für mein eigentliches Projekt eine function erstellt, die aber alles in einem dynamischen Array speichert.

Delphi-Quellcode:
  TAdapter_Rec = packed record
    AdapterName : String;
    FriendlyName: String;
    DHCP_Enabled: Boolean;
    IP_Address : String;
    Subnetmask : String;
    Gateway    : String;
  end;

  TAdapter_Array = array of TAdapter_Rec;


function NetzwerkInfos_auslesen(var Liste: TAdapter_Array; out ErrorCode: Integer): Boolean;
var
  i                : Byte;
  pAdapterList     : PIP_ADAPTER_INFO;
  pAdapterAddresses : PIP_ADAPTER_ADDRESSES;
  LenAdapter_List  : DWORD;
  LenAdapter_Address: DWORD;
  ErrorCode_List   : DWORD;
  ErrorCode_Address : DWORD;
  AdapterName      : String;

begin
  //Rückgabewerte vordefinieren
  Result   := false;
  ErrorCode := 0;

  //Variable initialisieren
  i                  := 0;
  LenAdapter_List    := 0;
  LenAdapter_Address := 0;
  ErrorCode_List     := 0;
  ErrorCode_Address  := 0;
  pAdapterList       := nil; // Alles auf 0 ==> Benötigte Buffergrösse ermitteln

  //AdapterList
  ErrorCode_List := GetAdaptersInfo(pAdapterList, LenAdapter_List);

  If ErrorCode_List <> ERROR_BUFFER_OVERFLOW then
    begin
      ErrorCode := ErrorCode_List;

      exit;
    end;

  //Länge auslesen, bei Fehler Fehlercode setzen und Procedure beenden
  ErrorCode_Address := GetAdaptersAddresses(0, 0, nil, nil, @LenAdapter_Address);

  If ErrorCode_Address <> ERROR_BUFFER_OVERFLOW then
    begin
      ErrorCode := ErrorCode_Address;

      exit;
    end;

  //Speicher anfordern
  pAdapterList     := AllocMem(LenAdapter_List);
  pAdapterAddresses := AllocMem(LenAdapter_Address);

  try
    //AdapterList auslesen
    ErrorCode_List := GetAdaptersInfo(pAdapterList, LenAdapter_List);

    //wenn das Auslesen der Adapter-List fehlgeschlagen hat, dann Fehlercode
    //setzen und Procedure beenden
    If ErrorCode_List <> ERROR_SUCCESS then
      begin
        ErrorCode := ErrorCode_List;

        exit;
      end;

    //AdapterAddresses auslesen
    ErrorCode_Address := GetAdaptersAddresses(0, 0, nil, pAdapterAddresses, @LenAdapter_Address);

    //wenn das Auslesen der Adapter-Addresses fehlgeschlagen hat, dann Fehlercode
    //setzen und Procedure beenden
    If ErrorCode_Address <> ERROR_SUCCESS then
      begin
        ErrorCode := ErrorCode_Address;

        exit;
      end;

    while Assigned(pAdapterList) do
      begin
        //Variable erhöhen
        inc(i);

        //Anzahl der Einträge erhöhen
        SetLength(Liste, i);

        Liste[Pred(i)].AdapterName := String(pAdapterList.AdapterName);
        Liste[Pred(i)].DHCP_Enabled := Boolean(pAdapterList.DhcpEnabled);
        Liste[Pred(i)].IP_Address  := String(pAdapterList.IpAddressList.IpAddress.S);
        Liste[Pred(i)].Subnetmask  := String(pAdapterList.IpAddressList.IpMask.S);
        Liste[Pred(i)].Gateway     := String(pAdapterList.GatewayList.IpAddress.S);

        pAdapterList := pAdapterList.Next;
      end;


    while Assigned(pAdapterAddresses) do
      begin
        for i := low(Liste) to high(Liste) do
          If Liste[i].AdapterName = String(pAdapterAddresses.AdapterName) then
            begin
              Liste[i].FriendlyName := String(pAdapterAddresses.FriendlyName);

              break;
            end;

        pAdapterAddresses := pAdapterAddresses.Next;
      end;

    //Rückgabewert
    Result := true;
  finally
    //
    FreeMem(pAdapterList);
    FreeMem(pAdapterAddresses);
  end;
end;
Mein Problem ist, dass sich FastMM am Ende vom Programm fast überschlägt weil Speicher nicht freigegeben worden ist.

Nun vermute ich, dass es mit dem SetLength zusammenhängt - ich fordere Speicher an, gib ihn aber nicht mehr frei.
Ich hab schon versucht, dort, wo ich die function aufrufe, am Ende die Variabe für "Liste" freizugeben (
Delphi-Quellcode:
SetLength(Variable, 0)
), aber auch das bringt nicht den gewünschten Erfolg.

Wie gib ich denn nun sauber den Speicher wieder frei?

himitsu 28. Okt 2012 15:41

AW: Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe
 
Zitat:

Delphi-Quellcode:
        pAdapterAddresses := pAdapterAddresses.Next;
      end;

  finally
    FreeMem(pAdapterAddresses);

Ich sagte doch, daß du dem FreeMem den Wert/Variable von GetMem geben muß. (nicht das NIL, welches nach dem letzen .Next rauskommt)
Und bei pAdapterList isses das Selbe.

Aber überschlagen ist bei diesen 2 größere Speicherblöcken wohl etwas übertrieben. :gruebel:

Helmi 28. Okt 2012 15:48

AW: Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe
 
Zitat:

Zitat von himitsu (Beitrag 1188770)
Zitat:

Delphi-Quellcode:
        pAdapterAddresses := pAdapterAddresses.Next;
      end;

  finally
    FreeMem(pAdapterAddresses);

Ich sagte doch, daß du dem FreeMem den Wert/Variable von GetMem geben muß. (nicht das NIL, welches nach dem letzen .Next rauskommt)
Und bei pAdapterList isses das Selbe.

Aber überschlagen ist bei diesen 2 größere Speicherblöcken wohl etwas übertrieben. :gruebel:

Ich kann dir gerade nicht folgen sorry!

Der Speicher wird ja angefordert:
Delphi-Quellcode:
  //Speicher anfordern
  pAdapterList     := AllocMem(LenAdapter_List);
  pAdapterAddresses := AllocMem(LenAdapter_Address);
und der Wert wird über FreeMem wieder freigegeben:
Delphi-Quellcode:
  finally
    //
    FreeMem(pAdapterList);
    FreeMem(pAdapterAddresses);
  end;
Oder meinst du ich muss mir den Originalwert von pAdapterList und pAdapterAddresses speichern um diese dann dem FreeMem zu übergeben?
(was jetzt Sinn machen würde)

[edit]
Also wenn ich mir den Originalwert speichere und diesen dann freigebe, dann gibt FreeMem Ruhe! - Danke für den Tip!!

Helmi 28. Okt 2012 15:48

AW: Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe
 
[QUOTE=himitsu;1188770]
Zitat:

Aber überschlagen ist bei diesen 2 größere Speicherblöcken wohl etwas übertrieben. :gruebel:
Was meinst du genau damit?

Himitsu editiert seine Beiträge immer so langsam - da kann es schon mal passieren, dass man doppelpostet :mrgreen:

himitsu 28. Okt 2012 16:02

AW: Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe
 
Rate mal, was in der Zwischenzeit mit dem Zeiger passiert, bei
Delphi-Quellcode:
pAdapterAddresses := pAdapterAddresses.Next;
?
Er zeigt auf was Anderes und über die Schleife wird so lange weitergemacht, bis NIL im pAdapterAddresses drinsteht.
Schau dir einfach nochmal meinen Beispielcode im anderem Thread an und achte auf diese Variable(n).

Zitat:

dass sich FastMM am Ende vom Programm fast überschlägt weil Speicher nicht freigegeben worden ist.
Es sind doch nur 2 "kleine" Lecks :angle:

Helmi 28. Okt 2012 17:10

AW: Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe
 
also ich hab es jetzt so gemacht:

Delphi-Quellcode:
function NetzwerkInfos_auslesen(var Liste: TAdapter_Array; out ErrorCode: Integer): Boolean;
var
  pAdapterList           : PIP_ADAPTER_INFO;
  pAdapterAddresses      : PIP_ADAPTER_ADDRESSES;
  pAdapterList_store     : PIP_ADAPTER_INFO;
  pAdapterAddresses_store : PIP_ADAPTER_ADDRESSES;

begin
  {...}

  //Speicher anfordern
  pAdapterList     := AllocMem(LenAdapter_List);
  pAdapterAddresses := AllocMem(LenAdapter_Address);

  //Größe des angeforderten Speichers merken, notwendig für das FreeMem
  //(die normalen Variablen werden nil und dadurch bleibt Speicher übrig)
  pAdapterList_store     := pAdapterList;
  pAdapterAddresses_store := pAdapterAddresses;

  try
  {...}
  finally
    //
    FreeMem(pAdapterList_store);
    FreeMem(pAdapterAddresses_store);
  end;
end;
Zitat:

Zitat von himitsu (Beitrag 1188774)
Es sind doch nur 2 "kleine" Lecks :angle:

Ja - das stimmt schon! Aber ich ruf die Procedure ggf. über einen Timer auf und dann summieren sich die kleinen Lecks.
"Kleine Lecks machen auch Speichermist"

sx2008 28. Okt 2012 18:41

AW: Problem mit Speicherfreigabe bei dynamischen Array als function-Übergabe
 
Delphi-Quellcode:
function NetzwerkInfos_auslesen(var Liste: TAdapter_Array; out ErrorCode: Integer): Boolean;
<== entweder ErrorCode als Result oder True/False als Erfolg/Misserfolg-Result aber Beides zusammen ist überbestimmt.


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