Autor Beitrag
IhopeonlyReader
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 21.04.14 21:01 
Guten Tag,
ich habe jetzt mal ein Server-Client spiel geschrieben.. Server wird pro Client ein paar Byte im Arbeitsspeicher größer, da ich pro Client (in Socket.Data) ein paar Daten ablege, die ich wenn der Client disconnected wieder freigebe...
Leider habe ich, wenn ein Client connected und wieder disconnected 12 Byte (oder sogar KB?) mehr im Arbeitsspeicher..
In der Summe der Clients ist es schnell über 1,5 GB wie ich gemerkt habe :/
ich versuche alles freizzugeben, aber wie soll ich Variablen vom Typ TDatetime oder sontiges freigeben?

Hier mal die Klasse die in die Data des Sockets gehangen werden:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
      fName: String;
      fImSpiel: Boolean;
      fSpielfeld: TSpielfeld;
      fDran: Boolean;
      fGegner: TCustomWinSocket;
      fFarbe: TBesetzt;
      fLastSendTime: TDateTime;
      SSSekTime: TDateTime;
      SSAnzSend: Cardinal;


Diese Daten werden auf Connecten des Sockets erstellt:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
 PD := TPDaten.Create; //so heißt die Klasse :D
PD.fName := ''//leer initialisiern
PD.fImSpiel := False;
PD.fDran := False;
PD.fLastSendTime := Now;
PD.SSAnzSend := 0;
PD.SSSekTime := Now;
Socket.Data := PD;


und wenn er disconnected, gebe ich so frei, leider scheinbar nicht alles:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
TPDaten(Socket.Data).fName := '';
Finalize( TPDaten(Socket.Data).fName );
TPDaten(Socket.Data).Free;
//FreeMem( Socket.Data, 27 ); //so ausprobiert oder auch ohne längenangabe...
TPDaten(Socket.Data).fSpielfeld.Free;



was habe ich vergessen? was muss ich wie freigeben?

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Mo 21.04.14 21:43 
Klassen müssen freigegeben werden, Records, Arrays und einfache Variablen (z.B. Integer) nicht. Naiv gesprochen: Alles was du von Hand erzeugst (mit .Create oder new() z.B.) muss auch wieder von Hand freigegeben (mit .Destroy/Free oder dispose() z.B.).

Zu deinem angegebenen Code beim Erzeugen genügt zum Freigeben ein
ausblenden Delphi-Quelltext
1:
TPDaten(Socket.Data).Free;					


Die Klasse TPDaten muss sich selbst darum kümmern, dass die eigenen privaten Attribute aufgeräumt werden. Dazu schreibst du einfach für die Klasse einen eigenen Destruktur (override nicht vergessen!)

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
type TPDaten = class
[...]
  public
    destructor Destroy; override;
end;


Die Klasse weiß ja selbst am besten, ob TSpielfeld eine Klasse ist und dann fSpielfeld.Free aufgerufen werden muss (oder ob es z.B. nur ein Zeiger ist und das Spielfeld nicht gelöscht werden soll).

Wenn du FastMM benutzt, sagt er dir beim Beenden des Programmes, wieviele Bytes Speicher geleaked sind und von welchem Typ sie sind (z.B. in deinem Fall TPDaten), was extrem nützlich ist und die beste mir bekannte Methode, mit Speicherlecks zurecht zu kommen. FastMM wurde mir auch mal hier im Forum empfohlen aus andrem Zusammenhang (es ist auch effizienter was Strings angeht), dem kann ich mich nun anschließen ;)

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)


Zuletzt bearbeitet von Xion am Mo 21.04.14 21:45, insgesamt 4-mal bearbeitet
mandras
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 432
Erhaltene Danke: 107

Win 10
Delphi 6 Prof, Delphi 10.4 Prof
BeitragVerfasst: Mo 21.04.14 21:43 
Ohne dein Programm näher zu kennen zwei Anmerkungen:

a) Freemem würde ich gar nicht verwenden (oder hast Du irgendwo GetMem eingesetzt?)
c) Wozu das Finalize? fName ist ein normaler langer String, der wird automatisch freigegeben
b) ich sehe eine Fehlermöglichkeit in der Reihenfolge:

ausblenden Delphi-Quelltext
1:
2:
TPDaten(Socket.Data).Free;
TPDaten(Socket.Data).fSpielfeld.Free;


tausche die beiden Zeilen einmal gegeneinander aus, möglicherweise ist das das Problem
(weil laut reiner Lehre Socket.Data nach dem Free bereits eigentlich nicht mehr existiert)

Wie gesagt, meine Vermutungen weil ich die Details nicht kenne.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 21.04.14 21:50 
b) ich hatte das Spielfeld schonmal davor freigegen, aber da es nicht immer exisitert, tritt teilweise ein fehler auf und es springt aus dem try-except block und Data.Free würde nicht mehr aufgerufen werden...
ich bringe fSpielfeld.free nun in das destroy ereignis von TPDaten...

aber darin liegt leider nicht der fehler :/

a) Freemem war auch nur ein versuch, nein getmem benutze ich nicht
c) finalize war auch nur ein Versuch, dispose hatte ich auch versucht :D

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Mo 21.04.14 22:47 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
b) ich hatte das Spielfeld schonmal davor freigegen, aber da es nicht immer exisitert, tritt teilweise ein fehler auf und es springt aus dem try-except block und Data.Free würde nicht mehr aufgerufen werden...

Also das klingt sehr unsauber und äußerst gefährlich. Du rufst ein .Free auf ein Objekt auf, das nicht existiert? Ok, solange dort nil hinterlegt ist, dann ist es nur unsauber, aber wenn nicht, wer weiß was da alles passieren kann. Im schlimmsten Fall ist dort im Speicher jetzt ein andres Objekt selben Typs und es wird gelöscht. Setze es initial auf nil und teste darauf, bevor du Free aufrufst (bzw. Free prüft selbst schon darauf). Es gibt auch FreeAndNil(obj), womit du gleich den Zeiger noch auf nil setzt.

Was dispose angeht kannst du auch mal hier gucken:
www.entwickler-ecke....ewtopic.php?t=111119

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 21.04.14 23:10 
Leider ist es so,
Wenn 2 Spieler gegeneinander spielen, so wird das Spielfeld erzeugt und bei den Daten beider unter fspielfeld hinterlegt.
Wenn jetzt Spieler 1 und 2 nacheinander disconnecten gibt Spieler 1 das Spielfeld schon frei, Spieler 2 dann unnötiger Weise nochmal
Das fix ich noch, aber darin liegt ja nicht der speicher Fehler an sich...
Und bei einem direkten verbinden und trennen existiert somit kein Spielfeld, darin kann also kein Fehler liegen

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 21.04.14 23:54 
user profile iconXion hat folgendes geschrieben Zum zitierten Posting springen:
Wenn du FastMM benutzt, sagt er dir beim Beenden des Programmes, wieviele Bytes Speicher geleaked sind und von welchem Typ sie sind (z.B. in deinem Fall TPDaten)
Und auch, wo der Speicher reserviert wurde inkl. Stacktrace.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 21.04.14 23:55 
Wie muss ich das brnutzen? Habe die ZIP runtergeladen und entpackt.. ( habe delphi 7PE)

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Di 22.04.14 08:03 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
Leider ist es so,
Wenn 2 Spieler gegeneinander spielen, so wird das Spielfeld erzeugt und bei den Daten beider unter fspielfeld hinterlegt.
Wenn jetzt Spieler 1 und 2 nacheinander disconnecten gibt Spieler 1 das Spielfeld schon frei, Spieler 2 dann unnötiger Weise nochmal

Das verstehe ich nicht ganz. Benutzt du gemeinsamen Speicher dafür? Sitzen die Spieler am selben Rechner? Denn sonst sind es zwei vollständig unterschiedliche Objekte. Der Client hat normalerweise eine Kopie der Daten des Severs. Es gibt also zwei unabhängige Spielfelder, die du auch beide freigeben musst.
PS: Da mag ich auch etwas daneben liegen, weil ich nicht ganz sicher bin was Socket.Data eigentlich genau macht. Hab aber grad auch keine Zeit das nachzuschlagen ;)



user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
Wie muss ich das brnutzen? Habe die ZIP runtergeladen und entpackt.. ( habe delphi 7PE)

Du musst nur die FastMM4.pas in deinem Projekt hinzufügen und in die Uses des Projekts (mit F8 zu finden) ganz oben als aller erste Unit einbinden.

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 22.04.14 09:07 
Und am besten den FullDebugMode einschalten. Meine entsprechenden Optionen hatte ich einmal hier gepostet:
www.entwickler-ecke.....php?p=682873#682873
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Di 22.04.14 11:01 
user profile iconXion hat folgendes geschrieben Zum zitierten Posting springen:
Benutzt du gemeinsamen Speicher dafür? Sitzen die Spieler am selben Rechner? Denn sonst sind es zwei vollständig unterschiedliche Objekte. Der Client hat normalerweise eine Kopie der Daten des Severs. Es gibt also zwei unabhängige Spielfelder, die du auch beide freigeben musst.

Socket.Data ist ein Pointer, hier habe ich die Klasse TPDaten hinterlegt... (Sieht man gut im OnConnect event (siehe Post 1)
TPDaten enthält wiederrum eine variable vom Typ TSpielfeld, da TSpielfeld auch eine Klasse ist, ist fSpielfeld eigentlich nur ein Pointer.
Wenn jetzt Spieler A gegen Spieler B spielt, so wird am Spielstart im Server ein neues Spielfeld (vom Typ TSpielfeld) erzeugt und sowohl bei Spielera in das fSpielfeld als auch bei Spieler B in das fSpielfeld gesetzt... so besitzen beide Spieler in ihren TPDaten ein Pointer auf das Spielfeld.

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Di 22.04.14 11:53 
So, der Fehler scheint dank FastMM4 behoben zu sein...
Fehler 1: Beim erstellen wurde ein Stream erstellt, der nicht freigegeben wurde da er mehrmals kopiert wurde.. (nicht im gepostet quelltext zu sehen)
Fehler 2: Beim schließen der Anwendung, wenn noch Clients verbunden waren, wurden diese nicht beendet sondern die Anwendung einfach geschlossen.. nun werden die Verbindungen vorher ordnungsgemäßg beendet und somit auch ihre Daten freigegeben

Ob mein server nun einem DDos angriff ohne Arbeitsspeicherüberlauf aushält wird noch getestet :D

Allerdings noch ein paar Fragen dazu am Rande...:
a) Wenn etwas nicht zwansläufig existiert (z.B. fSpielfeld vom Typ TSpielfeld und es nicht nil ist, sondern noch ein "veralteter" Wert drin steht, der woanders freigegeben wurde, wie überprüüfe ich ob fspielfeld jetzt noch freigegebn werden muss oder nicht?
aktuell mache ich es so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
try
fSpielfeld.free;
except
end;

so schmeißt free zwar einen fehler, aber der ist ja egal, da er "abgefangen" wird...
folgendes habe ich probiert:
ausblenden Delphi-Quelltext
1:
2:
if (fSpielfeld<>niland Assigned(fSpielfeld) then
 fSpielfeld.Free;

klappt nur leider nicht :/

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Di 22.04.14 11:54 
Benutzte statt FSpielfeld.Free einfach FreeAndNil(FSpielfeld).
Dann funktioniert der Test mit Assigned(FSpielfeld) auch zuverlässig.

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Di 22.04.14 12:10 
naja, es wird ja nicht die variable fSpielfeld zum feigeben verwendet!

beispiel
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
var Spielfeld1, Spielfeld2, DASSpielfeld: TSpielfeld;
begin
DasSpielfeld := TSpielfeld.create;
//Werte von "DasSpielfeld" initialisieren
Spielfeld1 := DAsSpielfeld;
Spielfeld2 := DASSpielfeld;

//irgendwie damit mit arbeiten
//und am ende
if Random(2)=1 then
Spielfeld2.Free; //hier würde auch Freeandnil(Spielfeld2) nichts bringen oder?

if Assigend( Spielfeld1 ) then
  Spielfeld1.Free;

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 22.04.14 13:08 
Benutze ein Interface und arbeite dann ausschließlich mit diesem Interface. Dann gibt Delphi dieses automatisch erst frei, wenn die letzte Referenz darauf weg ist. (Wenn das das ist, was du möchtest.)
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Di 22.04.14 13:10 
Nach Deinem Beispielquellcode zeigen DasSpielfeld, Spielfeld1 und Spielfeld2 alle auf die selbe Instanz.
Daher ist es egal, ob Du nun DasSpielfeld, Spielfeld1 oder Spielfeld2 freigibst. Es gibt immer die selbe Instanz frei.

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Di 22.04.14 13:15 
ja Nersgatt, das ist es ja.. sie sollen alle auf die selbe instanz zeigen!
Allerdings wird das spielfeld freigegeben, sobald 1 spieler disconnected (da bei einem 1 vs 1) das spielfeld nicht mehr benötigt wird.
Wenn der andere dann auch disconnected, dann will er das spielfeld auch freigeben, obwohl es schon freigegeben ist !

mir geht es nun allgemein um das beispiel, wie ich herausfinde ob ein pointer auf eine freigegebene instanz zeigt.

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Di 22.04.14 13:22 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
mir geht es nun allgemein um das beispiel, wie ich herausfinde ob ein pointer auf eine freigegebene instanz zeigt.

Genau wie ich sagte. Verwende FreeAndNil. Damit zeigen hinterher alle Pointer auf nil (die Pointer zeigen ja alle auf die selbe Stelle).

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Di 22.04.14 13:31 
wirklich?
ich dachte free and nil würde das machen
fSpielfeld1.Free;
fSpielfeld1 := nil;

weil dann wäre ja nur spielfeld 1 nil und spielfeld2 weiterhin auf die instanz gerichtet, die aber durch free freigegeben wurde

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Di 22.04.14 13:35 
Mea culpa. Du hast Recht. Ich nehm alles zurück und behaupte das Gegenteil :hair:

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)