dyn array kopieren mit a:=b und b dann nil setzen? [gelöst]

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: dyn array kopieren mit a:=b und b dann nil setzen?

Beitrag von mse »

laz847 hat geschrieben:Also kann man sagen SetLength(a,0) setzt a := nil, gibt aber den Speicher nur frei, wenn keine weitere Referenz auf den Inhalt besteht oder?
Ja.
Aber wie ist das wenn noch irgendwo eine Referenz hängt? Vermutlich ist "if declocked(realp^.refcount)" die Referenzzählung oder?
Ja.
Nehmen wir an ich habe Copy vergessen und durch a:= b die Referenz kopiert anstatt die Daten? Setz ich dann SetLength(b,0) hat a die Referenz auf die Daten, b wird nur genilt.
Dann wird fpc_dynarray_clear_internal >> freemem(p); nicht ausgeführt sondern nur p:=nil was exakt dieses Verhalten auslösen könnte oder?
Ja. "SetLength(b,n)" sorgt ausserdem dafür, dass a und b getrennte Speicherbereiche haben, "SetLength(b,length(n))" z.B. holt ein copy() nach.
http://www.freepascal.org/docs-html/ref ... 480003.3.1
Mach ich das inner Schleife und b ändert sich, bleibt doch da immer der "bisherige Inhalt" erhalten und wird nie freigegeben oder?

Code: Alles auswählen

while not(Terminated) do begin 
 
  tmp := nil;
 
  while(w2) do begin 
   [.......] //  tmp[]  wird resized und neu befüllt
  end;
 
  if(Length(globA[_pos]) <> Length(tmp)) then globA[_pos] := nil; // hier sollte dann beides gehen, SetLength(globA[_pos],0) oder nil, da nur eine referenz auf globA[_pos] besteht, tmp war nil und enthält neue daten 
 
  // nimmt man aber diese zeile raus und nutzt weder setlength(a,0) noch nil bleibt doch da was im speicher liegen oder?
 
Nein. Bei der Zuweisung "b:= a" wird "incref(a); decref(b); pointer(b):= pointer(a)" ausgeführt. "decref(b)" gibt den Speicher frei falls der Referenzzähler 0 erreicht.

Code: Alles auswählen

 
  globA[_pos] := tmp; // ist es sicher das bei der neuen zuweisung ohne vorher setlength(globA[_pos],0) oder nil zu setzen der speicher des bisherigen inhalts SOFORT freigegeben wird, auch wenn wir den scope nicht verlassen sondern das in eine while tun?
 
end;
Im Prinzip schon, Free Pascal legt aber manchmal Zwischenvariablen an und gibt ausdrücklich keine Garantien über solch "internes Verhalten".
Ich habe nicht das ganze Thema gelesen, warum bist du denn auf sofortiges Freigeben des Speichers angewiesen?
Ich kann kein Assembler aber ich sehe die call's auf die fpc Routinen. Wie mache ich diese Ausgaben sichtbar und wie / wo finde ich die entsprechenden Routinen?
Man kann mit -al kompilieren, dann erzeugt FPC assembler Dateien:
http://www.freepascal.org/docs-html/use ... 450005.1.4
Oder man benutzt das assembler-Fenster:
assembler.png
Das ist zwar MSEide, Lazarus hat aber ebenfalls ein assembler-Fenster. Die Routinen für dynamische Arrays sind in rtl/inc/dynarr.inc.

laz847
Beiträge: 114
Registriert: Mi 18. Jun 2014, 16:39

Re: dyn array kopieren mit a:=b und b dann nil setzen?

Beitrag von laz847 »

Logisch, die Speicherallokierung braucht dabei ja nicht so oft durchgeführt werden. Also nix mit SetLength(a, 0), naja, lag wohl etwas zu weit zurück
Alles kein Problem, auch wenn manche evtl. genervt sind, dass ich so bis ins Detail nachfrage, wie man in 2 Fällen sehen kann, nicht ganz unberechtigt.
Ja. "SetLength(b,n)" sorgt ausserdem dafür, dass a und b getrennte Speicherbereiche haben, "SetLength(b,length(n))" z.B. holt ein copy() nach.
Genau, das fiel mir auch noch auf, wenn man :

Code: Alles auswählen

SetLength(a,10);
 
b := a; // setzt ist Length(b) auch 10, beide Arrays zeigen auf den selben Speicher, setzt man nun
 
SetLength(b,12); // werden beide Arrays kopiert + "getrennt", Length(a) ist 10 und Length(b) ist 12 + beide verweisen auf unterschiedliche Speicherbereiche << das meinst du mit copy nachgeholt denke ich
 
"decref(b)" gibt den Speicher frei falls der Referenzzähler 0 erreicht. [...] Free Pascal legt aber manchmal Zwischenvariablen an und gibt ausdrücklich keine Garantien über solch "internes Verhalten".
Ok, danke dann bin ich aber auf jeden Fall auf der sicheren Seite wenn ich da nochmal nil setze zuvor.
Ich habe nicht das ganze Thema gelesen, warum bist du denn auf sofortiges Freigeben des Speichers angewiesen?
Weil das im while not(terminated) in 10 Threads tagelang oder wochenlang läuft ohne den Scope jemals zu verlassen. Dabei ändert sich die Length(tmp) immer wieder und ich will sichergehen das sich da kein Müll ansammelt.
Allein am Ramverbrauch ist das schwer zu sehen, da sich da gleichzeitig noch einige andere Arrays bzw. Daten ändern.

Danke für den Link, endlich hab ich mal ne Übersicht über die Optionen, hab ich vor kurzem gesucht :D.

War ein ziemlich interessanter Ausflug, was da so im Inneren passiert, wenn man einfach nur mal a := b setzt :D. Für mich ist jetzt klar wann ich es wie nutzen kann, wann ich copy benutzen muss, worauf man unbedigt achten muss.

Vielen lieben Dank für Eure Geduld!

PS: Ich glaub Assembler nehme ich mir irgendwann wann mal ganz in Ruhe vor :D Trotzdem danke für die nützlichen Infos!

Antworten