AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Speicherverwaltung bei Basisdatentypen

Ein Thema von Getox · begonnen am 13. Mär 2019 · letzter Beitrag vom 13. Mär 2019
Antwort Antwort
Getox

Registriert seit: 28. Dez 2012
155 Beiträge
 
Delphi XE3 Professional
 
#1

Speicherverwaltung bei Basisdatentypen

  Alt 13. Mär 2019, 10:37
Delphi-Version: XE3
Ich habe mal eine grundsätzliche Frage, was ich einfach noch nicht verstehe.

Wenn ich ein Objekt erzeuge wird ja der Speicher reserviert und erst wieder zum erneuten beschreiben freigegeben, wenn ich es wieder Freigebe.

Wie Funktioniert das eigentlich bei den Basisdatentypen? Woher weiß Delphi wann der Speicher wieder freigegeben werden kann? Bei Lokalen Variablen vermutlich wenn sie den Gültigkeitsbereich verlassen... aber wie ist das mit Objektvariablen? Geben Objekte automatisch den Speicher ihrer Variablen frei, wenn sie zerstört werden? Und wie ist das bei globalen Variablen?

Ich weiß... doofe frage, aber irgendwie interessiert mich das
Ist ein Nilpferd ein Pferd, das nicht vorhanden ist?
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#2

AW: Speicherverwaltung bei Basisdatentypen

  Alt 13. Mär 2019, 10:43
Lokale Variablen werden auf dem Stack abgelegt. Die werden sobald die Funktion verlassen wird (wie du sagtest) ungültig, bzw. der Speicher wird früher oder später durch lokale Variablen oder Rücksprungadressen anderer Funktionen überschrieben.
Variablen von Objekten liegen einfach im für das Objekt reservierten Speicherbereich. Wenn das Objekt freigegeben wird, werden damit auch die Variablen des Objekts freigeben bzw. liegen in ungültigem/nicht reserviertem Speicher.
Bei globalen Variablen bin ich mir nicht zu 100% sicher, aber ich denke für die wird schon beim Laden der .exe Speicher reserviert und der wird auch erst wieder freigegeben wenn die .exe (bzw. das entprechende Modul) beendet/entladen wird.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Getox

Registriert seit: 28. Dez 2012
155 Beiträge
 
Delphi XE3 Professional
 
#3

AW: Speicherverwaltung bei Basisdatentypen

  Alt 13. Mär 2019, 12:08
Danke. Durch das Stichwort "Stack" habe ich mich erinnert, dass mir mein Ausbilder damals Etwas über Heap und Stack erklärt hat. Danach habe ich mal jetzt gesucht und habe folgenden Thread gefunden:
https://www.delphipraxis.net/162461-...erschiede.html
Das hat mich mit meinem Verständnis auf jeden Fall noch einmal ein ganzen Stück vorran gebracht.

Was ich jetzt verstanden habe:
Lokale Variablen landen auf dem Stack. Dort wird jeweils ein "Slot" mit einer bestimmten Größe reserviert. Bei einer Variable mit einer festen Größe wie z.B. Integer wird der reservierte Speicher wieder Freigegeben, wenn die Funktion verlassen wird und die Variable wieder vom Stack entfernt wird.

Bei einem Objekt passiert das selbe mit der Referenz auf das Objekt. Das Objekt liegt auf dem Heap und die Variable auf dem Stack zeigt auf die Heap-Adresse des Objektes. Wenn ich dieses nicht manuell freigebe, wird die Referenz beim verlassen der Funktion freigegeben und das Objekt liegt ohne Referenz unauffindbar im Heapspeicher.

Anderes Szenario: Ich habe eine lokale Variable für eine Objektreferenz. Diese übergebe ich als Parameter an eine weitere Funktion, in der ich das Objekt freigebe. Wenn ich nun in die ursprüngliche Funktion zurückkehre, habe ich dort noch die Referenz in der lokalen Variable gespeichert, die aber nun an einen Ort im Heap zeigt, wo überhaupt kein Objekt mehr liegt.

Was ich jetzt noch nicht verstehe:
Wie ist das bei Strings? Diese sind doch variabel ihrer Größe, also müssten sie doch theoretisch eher auf dem Heap landen, oder? Aber warum muss ich Strings dann nicht manuell erstellen und freigeben? Ich hatte auch schon mal ein Leak durch einen String in einem Record, den ich erstmal wieder leeren musste. Aber ich setze ja auch nicht jedesmal jeden String wieder auf '', bevor eine Funktion verlassen wird...
Ist ein Nilpferd ein Pferd, das nicht vorhanden ist?
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#4

AW: Speicherverwaltung bei Basisdatentypen

  Alt 13. Mär 2019, 12:11
Ein string ist auch ein Referenz-Typ, allerdings zusätzlich mit einem Referenz-Zähler. Und wenn der Referenz-Zähler auf 0 geht, dann wird der Bereich auf dem Heap automatisch freigegeben.
  Mit Zitat antworten Zitat
peterbelow

Registriert seit: 12. Jan 2019
Ort: Hessen
701 Beiträge
 
Delphi 12 Athens
 
#5

AW: Speicherverwaltung bei Basisdatentypen

  Alt 13. Mär 2019, 12:49
Ich habe mal eine grundsätzliche Frage, was ich einfach noch nicht verstehe.

Wenn ich ein Objekt erzeuge wird ja der Speicher reserviert und erst wieder zum erneuten beschreiben freigegeben, wenn ich es wieder Freigebe.

Wie Funktioniert das eigentlich bei den Basisdatentypen? Woher weiß Delphi wann der Speicher wieder freigegeben werden kann? Bei Lokalen Variablen vermutlich wenn sie den Gültigkeitsbereich verlassen... aber wie ist das mit Objektvariablen? Geben Objekte automatisch den Speicher ihrer Variablen frei, wenn sie zerstört werden? Und wie ist das bei globalen Variablen?

Ich weiß... doofe frage, aber irgendwie interessiert mich das
Wie Michael in seiner Antwort schon sagte liegen lokale Variablen (in einer Methode/procedure/function deklariert) auf dem Call-Stack und werden damit (zumindest für Value-Typen) automatisch "abgeräumt" wenn die Methode verlassen wird. Für Reference-Typen enthalten die lokalen Variablen aber nur Pointer auf anderswo angelegten Speicher und der Compiler verwaltet diesen Speicher nur für einige besondere Typen automatisch (normalerweise per reference-counting). Das sind insbesondere String, Ansistring, Widestring, Interface-Typen, dynamische Arrays, anonyme Methoden. Was Du selbst im Code an Objekten oder Heap memory anlegst und in lokalen Variablen ablegst must Du auch am Ende der Methode selbst wieder freigeben (Stichwort try ... finally), sonst hast Du ein Speicherleck.

Für Variablen (Felder) in einem Objekt gilt Ähnliches: Das Objekt selbst bekommt, wenn es erzeugt wird, einen Speicherblock vom Memory manager, der den Platz für alle Felder enthält (und noch einiges mehr). Wenn das Objekt zerstört wird geht der Block an den Memory manager zurück und vorher werden auch für alle Felder, die compiler-managed reference types enthalten (siehe oben) die reference counts um eins vermindert und damit eventuell der Speicherblock, auf den die Referenz verweist, freigegen. Für andere reference types (Objekte, pointer auf Heap-Memory) gilt das vorstehend gesagte: was Du selbst angelegt hast (normalerweise im Constructor der Klasse) mußt Du auch selbst freigeben (normalerweise im Destructor der Klasse), sonst gibt es ein memory leak. Kompliziert wird's, wenn für erzeugte Objekte Referenzen an verschiedenen Stellen im Kode existieren, da muss man sich sehr genau überlegen, wer nun für die Verwaltung der Lebensdauer veranwortlich ist.

Für globale Variablen gibt es ein data segment im EXE selbst, das aus der Datei in den Speicher geladen wird und eine feste Größe hat. Dieser Speicher existiert solange die Anwendung läuft; Variablen, die nicht explizit in der Deklaration initialisiert wurden, sind auf 0 bzw. nil gesetzt. Globale Variablen in Units, die compiler-managed types enthalten, werden im Finalization-Kode der Unit freigegeben (über den reference count). Der Compiler erzeugt dabei automatisch die Finalization section, wenn der Programmier nicht explizit eine angegeben hat. Für andere reference types gilt wieder: was man selbst angelegt hat (normalerweise in einer Initialization section) muss man auch wieder freigeben (normalerweise in einer Finalization section).

Komponenten (alles, was von TComponent) abstammt) machen die Sache noch undurchsichtiger, da diese Klasse einen Mechanismus für die Verwaltung der Lebensdauer per "ownership" enthält. Wenn man (oder die VCL beim Laden eines DFM-Files) eine Komponente mit einem Owner anlegt wird sie automatisch zerstört, wenn der Owner ablebt. Da alle autocreated Forms und Datamodules das Application-Objekt als Owner haben und dieses von der VCL explizit in der Finalization-Sektion zerstört wird braucht man sich um die von der IDE erzeugten Form-Variablen gemeinhin keine Gedanken machen. Für TControls gilt dazu noch: wenn der Parent das Zeitliche segnet bringt er vorher noch alle seine Kinder um, was normalerweise eine fette Schlagzeile in der Bildzeitung wert wäre.

Eine Sache sollte man aber immer im Hinterkopf behalten: wenn man ein Objekt zerstört (seine Free-Methode aufruft) oder einen Heap-Pointer freigibt (Dispose, FreeMem etc.) wird dadurch die Variable, in der die referenz abgelegt wurde, [B]nicht[B] automatisch auf nil gesetzt! Wenn man die Referenz dann später versehendlich nochmal verwendet hat das oft seltsame Fehler zur Folge...
Peter Below
  Mit Zitat antworten Zitat
Getox

Registriert seit: 28. Dez 2012
155 Beiträge
 
Delphi XE3 Professional
 
#6

AW: Speicherverwaltung bei Basisdatentypen

  Alt 13. Mär 2019, 13:10
Vielen Dank peterbelow für die ausführliche und verständliche Erklärung. Nun habe ich keine weiteren Fragen mehr.

Zum Abschluss ein Witz, der mir eben in den Sinn kam:
Um ein Memoryleak zu identifizieren benötigt man heap- und stackfeste Beweise
Ist ein Nilpferd ein Pferd, das nicht vorhanden ist?
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:23 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