Dynamische Array erzeugt in const ein Speicher Leak

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von Mathias »

Dieses MiniProgram erzeugt ein Speicher Leak.

Code: Alles auswählen

uses
  heaptrc;

  procedure test;
  const
    ar: array of byte = nil;
  begin
    SetLength(ar, Length(ar) + 1);
    WriteLn(Length(ar));
  end;

var
  i: integer;
begin
  for i := 0 to 3 do test;
end.   
Ausgabe:

Code: Alles auswählen

1
2
3
4
Heap dump by heaptrc unit of /home/tux/fpcupdeluxe_stable/projects/project1
1 memory blocks allocated : 74/96
0 memory blocks freed     : 54/72
1 unfreed memory blocks : 20
True heap size : 32768
True free heap : 32512
Should be : 32552
Call trace for block $00007F5BCC478100 size 20
  $00000000004010D5  TEST,  line 10 of project1.lpr
  $0000000000401144  main,  line 17 of project1.lpr
Kann man dies vermeiden, ohne das man die Array global deklariert ?
Ich bin darauf gestossen, weil ich etwas ausprobieren wollte.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 10468
Registriert: Mo 11. Sep 2006, 19:01

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von theo »

Keine Ahnung was du damit bezweckst, aber warum machst du es nicht einfach nil wenn du es nicht mehr brauchst?

Code: Alles auswählen

 begin
   SetLength(ar, Length(ar) + 1);
   WriteLn(Length(ar));
   ar:=nil;
 end; 

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von fliegermichl »

Wenn eine lokale Variable einer Prozedur als const deklariert wird, bleibt deren Inhalt über mehrere Aufrufe erhalten.
Das sieht man ja auch an dem angezeigten Ergebnis.

Das wiederum sorgt dafür, daß der Compiler diese nach beenden der Prozedur nicht löscht.

Wenn du es als var deklarierst, wird das Array automatisch freigegeben und du erhältst 4 mal 1 als Ausgabe.

Einen Tod muß man halt sterben.

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von six1 »

was ich nicht ganz verstehe ist, dass man diese Konstante über setlength definieren kann... ist doch "const"...
Gruß, Michael

Benutzeravatar
theo
Beiträge: 10468
Registriert: Mo 11. Sep 2006, 19:01

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von theo »

six1 hat geschrieben:
So 2. Apr 2023, 11:19
was ich nicht ganz verstehe ist, dass man diese Konstante über setlength definieren kann... ist doch "const"...
Ja, das verstehe ich auch nicht ganz, ist aber so:
https://www.freepascal.org/docs-html/prog/progsu42.html

Sonst s.a. https://lists.freepascal.org/pipermail/ ... 53892.html

Benutzeravatar
six1
Beiträge: 782
Registriert: Do 1. Jul 2010, 19:01

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von six1 »

trotz dieser Beschreibungen finde ich es immer noch seltsam, denn folgendes funktioniert:

Code: Alles auswählen

const
  ar: array of byte = nil;
begin
  SetLength(ar, Length(ar) + 1);
  ar[high(ar)]:=$A5;
  showmessage(inttostr(Length(ar)));
end;    
also die Zuweisung eines Wertes auf ein Element des CONST Array!
Was ist denn jetzt "CONST"? ar? Aber ar ist doch letztendlich nur eine Anzahl Bytes und ein Pointer drauf, oder?

für mich verhält sich dieses dynamische Array wie eine Variable, ohne dass diese beim Beenden der Funktion zerstört wird.

Code: Alles auswählen

const
  ar: array of byte = nil;
begin
  SetLength(ar, Length(ar) + 1);
  ar[high(ar)]:=$A5;
  showmessage(inttostr(Length(ar)));
  SetLength(ar, 0);
end; 
komplett sinnbefreit, oder?

Das macht Sinn, MEINER Meinung nach:

Code: Alles auswählen

const
   Test1: array of LongInt = (1, 2, 3);
Ein dynamisches Array ist MEINEM Verständnis nach NIEMALS "CONST"
Zuletzt geändert von six1 am So 2. Apr 2023, 14:59, insgesamt 8-mal geändert.
Gruß, Michael

u-boot
Beiträge: 306
Registriert: Do 9. Apr 2009, 10:10
OS, Lazarus, FPC: Ubuntu 9.10 (L 0.9.28 FPC 2.2.4)
CPU-Target: 32Bit
Wohnort: 785..

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von u-boot »

Danke fliegermichl für die Aufklärung. Mich hat sehr gewundert, wie das Beispiel überhaupt so weit kommen kann.

theo hat geschrieben:
So 2. Apr 2023, 09:48
Keine Ahnung was du damit bezweckst, aber warum machst du es nicht einfach nil wenn du es nicht mehr brauchst?

Code: Alles auswählen

 begin
   SetLength(ar, Length(ar) + 1);
   WriteLn(Length(ar));
   ar:=nil;
 end; 
Ich hätte jetzt auf setlength(ar, 0)getippt. Aber wenns mit nil klappt, um so besser.

Kann es sein dass im Wiki die 'konstanten' dynamischen arrays noch nicht komplett mitbeachtet wurden ?:
wiki.freepascal.org hat geschrieben: Dynamic arrays are reference counted. Calling setLength(myDynamicArrayVariable, 0) virtually does myDynamicArrayVariable := nil and decreases the reference count. Only when the reference count hits zero, the memory block is released.

.......

Nonetheless, dynamic arrays are finalized automatically. It is not necessary to manually setLength(…, 0) on all your references when the program comes to end, or when leaving a scope in general.
Ubuntu 9.10 (L 0.9.28 FPC 2.4.x)

Benutzeravatar
theo
Beiträge: 10468
Registriert: Mo 11. Sep 2006, 19:01

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von theo »

u-boot hat geschrieben:
So 2. Apr 2023, 11:46
Ich hätte jetzt auf setlength(ar, 0)getippt. Aber wenns mit nil klappt, um so besser.
Da gibt es wohl verschiedene Varianten. Finalize(ar) müsste auch gehen.

@six1: Vielleicht kann PascalDragon da Licht hinein bringen.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von Mathias »

six1 hat geschrieben:
So 2. Apr 2023, 11:19
was ich nicht ganz verstehe ist, dass man diese Konstante über setlength definieren kann... ist doch "const"...
Dies wird das Gleiche sein, wie bei eine einfachen Variable. In meinem Beispiel ist "ar" nicht anderes als ein Pointer, welcher auf die dynamische Array zeigt. Und ein Pointer ist auch eine einfache Variable.

Dies spuckt auch 1,2,3,4 aus:

Code: Alles auswählen

procedure test;
const
  ci:byte = 0;
begin
  Inc(ci);
  WriteLn(ci);
end;

var
 i: integer;
begin
 for i := 0 to 3 do test;
end. 
Was ist denn jetzt "CONST"? ar? Aber ar ist doch letztendlich nur eine Anzahl Bytes und ein Pointer drauf, oder?
Der Bezeichner "const" finde ich auch etwas unglücklich gewählt., const ist in meinen Augen etwas starres unveränderbares.
So etwas in dieser Art wäre eindeutiger:

Code: Alles auswählen

var
  ci:byte = 0; static;       
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von wp_xyz »

Ich benutze in Laz/FPC nie die Initialisierung von Variablen mit "const" - was so deklariert wurde, ist konstant und wird nicht mehr geändert, basta! Wenn ich initialisierte Variablen benötige, schreibe ich "var" und den Initialisierungswert dahinter.

In dem Beispiel würde ich also schreiben (die Initialisierung des Arrays ist hier sinnvoll, um dem Compiler die Warning wegen der nicht initialisierten Variablen auszutreiben):

Code: Alles auswählen

  procedure test;
  var
    ar: array of byte = nil;
  begin
    SetLength(ar, Length(ar) + 1);
    WriteLn(Length(ar));
  end;
Was dann aber das Problem hätte, dass die Variable "ar" bei jedem Aufruf von test neu gesetzt wird. Aber das ist das generelle Problem mit diesem Code: Wieso eine Variable lokal deklarieren, wenn sie globale Gültigkeit haben soll? Das ist übelster C-Stil...

Richtig wäre meiner Meinung nach:

Code: Alles auswählen

var
  ar: array of byte = nil;

  procedure test;
  begin
    SetLength(ar, Length(ar) + 1);
    WriteLn(Length(ar));
  end;  

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von fliegermichl »

wp_xyz hat geschrieben:
So 2. Apr 2023, 14:23
Ich benutze in Laz/FPC nie die Initialisierung von Variablen mit "const" - was so deklariert wurde, ist konstant und wird nicht mehr geändert, basta! Wenn ich initialisierte Variablen benötige, schreibe ich "var" und den Initialisierungswert dahinter.
Ich vermute, daß das wegen Delphi so gemacht wurde. In Turbopasal gab es keine initialisierten Variablen.
Da war const wirlich nur const und konnte nachher nicht mehr verändert werden.

Ja und du hast Recht. In lokalen Funktionen deklarierte const Werte sind global.
Einzig der Zugriff darauf ist auf die definierende Prozedur/Funktion beschränkt.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von wp_xyz »

Da täuscht dich deine Erinnerung: das änderbare "const" gab es schon unter TurboPascal, habe es gerade nochmal ausprobiert. Das initialisierbare "var" dann unter Delphi, evtl. nicht gleich von Anfang an; aber es gab auch die Direktive {$WRITEABLE CONST ON} bzw. {$J+}, die den Spuk erst aktivierte (https://docwiki.embarcadero.com/RADStud ... Konstanten).

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von siro »

Ja, es klingt komisch, eine Konstante zu ändern,
Das Pendant in C heisst static
Somit konnte ich meine Funktionen durch diese Art und Weise völlig unkompliziert von C anch Pascal wandeln.
Die Variablen bleiben während des gesamten Progrmmlaufs erhalten und haben eine feste Adresse,
also wie eine Global. Nur der Zugriff ist beschränkt, nämlich nur innerhalb der Funktion bzw. Procedure.
Wobei: bei SetLength .... :roll: vermutlich nicht...

mein ursprünglicher Code in "C"

Code: Alles auswählen

S32  FilterTP(S32 value)
{ static S32 d    = 200;      // Filter Centerfrequenz (Wert)
  static S32 n    = 0;
  static S32 rest = 0;
         S32 xx;

  value = value - n;
  xx    = value * d;
  rest = (xx+rest) % 65536;
  xx   = (xx+rest) / 65536;
  n = n + xx;
  
  return n;
}
und nun in Pascal mit den loakeln statischen Variablen:

Code: Alles auswählen

// !!!!! die mit const deklarierten Variablen
// müssen statisch local sein oder global

function FilterTP(value:Integer):Integer;   // Tiefpass
const d    : Integer = 200;      // Filter Centerfrequenz (Wert)
const n    : Integer = 0;
const rest : Integer = 0;
  var   xx : Integer = 0;
begin
  value:= value - n;

  xx   := value * d;      // d ist ja schon mit 65536 multipliziert
  rest := (xx + rest) MOD 65536;    // wir muessen jetzt durch 65536 teilen
  xx   := (xx + rest) DIV 65536;    // und den jeweiligen rest uns merken
  n    := n + xx;

  result:=n;
end;

Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von Mathias »

Ja, es klingt komisch, eine Konstante zu ändern,
Dies ist irgendwie auch doof und kann zu Fehlern führen. Somit ist es unter Umständen möglich eine wichtige Konstante zu ändern.

Da habe ich gerade was lustiges gefunden, " unimplemented", was das wieder ist ?

Code: Alles auswählen

const
  CM_BASE                 = $B000;
...
  CM_GOTFOCUS             = CM_BASE + 2 unimplemented;
  CM_LOSTFOCUS            = CM_BASE + 3 unimplemented;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Dynamische Array erzeugt in const ein Speicher Leak

Beitrag von siro »

caption:=IntToStr(CM_GOTFOCUS); ergibt 45058

CM_BASE ist 45056
+2 logischerweise 45058

habe ich nur dies hier gefunden:
https://wiki.freepascal.org/modifier

hint directives

If {$modeSwitch hintDirectives+}, the following hint modifiers are available too:

deprecated
experimental
platform
unimplemented

These “modifiers” actually have no effect on the generated code, but can be promoted to errors using {$warn}
(so, for example, in order to ensure deprecated functionality is not used in a release version).


kann ich jetzt auch nix mit anfangen.... :?
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Antworten