![]() |
Datenbank: MySQL • Version: 5.5 • Zugriff über: SqlDB
Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Erstmal hallo zusammen,
normalerweise durchforste ich, wenn ich beim Programmieren nicht weiterkomme, solange die Delphipraxis, Google etc., bis ich das Problem gelöst habe. Daher ist dies seit fast vier Jahren, da ich einen Account habe, auch meine erste Frage. Seit Tagen schlage ich mich damit rum und komme einfach nicht weiter! Das sind die Gegebenheiten: Ich programmiere unter Lazarus (genau Typhon) für Linux x64 einen Spielserver für ein Spiel, das ich vor einiger Zeit programmiert habe. Dieser Server nutzt den TCP-Server der Indykomponenten. Die Klienten (IdTCPClient) verbinden sich nun mit diesem Server, der daraufhin für jede Verbindung eine Datenbankverbindung per SqlDB zu meiner MySQL-Datenbank auf demselben Hostsystem anlegt. Dies geschieht über drei Komponenten (TMySQL55Connection, TSQLTransaction, TSQLQuery), die erstellt und in einem Record zusammengefasst werden (Firstem ist der Name des Spiels):
Delphi-Quellcode:
Der Zeiger auf dieses Record wird im Tag der Verbindung zum Client gespeichert. Das Ganze sieht dann so aus:
type
PFiRe = ^TFirstemRecord; TFirstemRecord = record Name: String; Spiel: String; Angemeldet: Boolean; Verbindung: TMySQL55Connection; Anfrage: TSQLQuery; Transaktion: TSQLTransaction; Context: TIdContext; end;
Delphi-Quellcode:
Nun zu meinem eigentlichen Problem:
procedure TFirstemServer.TCPServerConnect(AContext: TIdContext);
var A: PFiRe; begin //Anmkerkung an die Delphipraxis: Die Verbindung zwischen Client und Server findet per SSL(IdServerIOHandlerSSLOpenSSL) verschlüsselt statt. if (AContext.Connection.IOHandler is TIdSSLIOHandlerSocketBase) then TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := false; Writeln('Klient verbunden: ' + AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.PeerPort)); AContext.Connection.Tag := Int64(New(PFiRe)); A := PFiRe(AContext.Connection.Tag); A^.Context := AContext; A^.Angemeldet := false; //MySQL-Verbindungskomponente erzeugen: A^.Verbindung := TMySQL55Connection.Create(nil); with A^.Verbindung do begin HostName := SQL_Adresse; DatabaseName := SQL_Datenbankname; UserName := SQL_Nutzername; Password := SQL_Nutzerpasswort; CharSet := 'UTF8'; end; //SQL-Transaktionskomponente erzeugen: A^.Transaktion := TSQLTransaction.Create(nil); //SQL-Querykomponente erzeugen: A^.Anfrage := TSQLQuery.Create(nil); A^.Anfrage.UniDirectional := true; //Soll angeblich ein Speicherleck in Bezug auf das Caching verhindern -> Pustekuchen. //Zuweisungen: A^.Verbindung.Transaction := A^.Transaktion; A^.Transaktion.DataBase := A^.Verbindung; A^.Anfrage.DataBase := A^.Verbindung; A^.Anfrage.Transaction := A^.Transaktion; end; Wenn ein Klient sich verbindet und die Verbindung kurz darauf wieder trennt, ohne eine Aktion ausgeführt zu haben, führt dies zu keinerlei Speicherlecks. Wenn er aber dann z.B. eine Anmeldung durchführt, woraufhin der Server die Zugangsdaten aus der MySQL-Datenbank überprüft, erzeugt dies merkwürdige Speicherlecks (die ich gleich näher erläutern werde). Hier der Quelltext, bei dem das Speicherleck erzeugt wird:
Delphi-Quellcode:
Lasse ich dieses Stück draußen, entstehen ebenfalls keine Speicherlecks. Und ich verstehe nicht warum.
with A^.Anfrage do
begin SQL.Text := 'SELECT passwort FROM nutzer WHERE name = :NAME'; Params.ParamByName('NAME').AsString := Nutzername; Open; Kennwort_db := FieldByName('passwort').AsString; Close; end; Nun um das Ganze noch verrückter zu machen: Die Speicherlecks werte ich mithilfe der Heaptrc-Unit von Lazarus aus und erhalte folgendes Ergebnis:
Code:
Und das Ganze 23 mal. Manchmal steht die letzte Zeile doppelt dort. Indyversion ist 10.6.2.20.
Call trace for block [Wechselnde Adresse] size [immer um die 30]
[$48153B] line 185 of source/IdContext.pas [$4F53C1] line 136 of source/IdTask.pas [$4DEC7D] line 697 of source/IdThread.pas [$4DDFCF] line 428 of source/IdThread.pas Die Zeilen führen alle letztlich zu einer abstrakten Run-Methode und einem Boolean. Warum löst eine SQL-Verbindung Speicherlecks in Indy aus? Ich hoffe, ihr könnt mir helfen. Benedikt |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Hallo,
Indy hat ein paar mem leaks, wo sich keiner rantraut, weil es zu kompliziert ist. Die sind aber statisch (einige globale Variablen, die einmal erzeugt und danach nicht freigegeben werden), nicht 23*x oder sowas .
Delphi-Quellcode:
Wo erfolgt denn die Freigabe dieser Klassen?
AContext.Connection.Tag := Int64(New(PFiRe));
A^.Transaktion := TSQLTransaction.Create(nil); A^.Anfrage := TSQLQuery.Create(nil); Fehlendes Close (Zur Sicherheit);
Delphi-Quellcode:
with A^.Anfrage do
begin Close; SQL.Text := 'SELECT passwort FROM nutzer WHERE name = :NAME'; Ich habe nicht die gleiche Version, bei mir ist das aber alles Code des Exception-Handlings bei deiner Zeilen-Angabe. Heiko |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Zitat:
Delphi-Quellcode:
versuch es mal so.
Kennwort_db := ' - undefined -';
begin A^.Anfrage.SQL.Text := 'SELECT passwort FROM nutzer WHERE name = :NAME'; A^.Anfrage.Params.ParamByName('NAME').AsString := Nutzername; A^.Anfrage.Open; if not A^.Anfrage.EOF then Kennwort_db := FieldByName('passwort').AsString; A^.Anfrage.Close; end; Gruß K-H |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Vielen Dank für eure Antworten!
Zitat:
Zitat:
Delphi-Quellcode:
Funktioniert auch. Da werden keine Speicherlecks gemeldet.
procedure TFirstemServer.TCPServerDisconnect(AContext: TIdContext);
var A: PFiRe; begin WriteLn('Klient getrennt: ' + AContext.Binding.PeerIP + ':' + IntToStr(AContext.Binding.PeerPort)); A := PFiRe(AContext.Connection.Tag); with A^ do begin Anfrage.Free; Transaktion.Free; Verbindung.Free; end; Dispose(A); end; Zitat:
Zitat:
|
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Hallo,
sind das die einzigen Lecks? Ist das FastMM4 oder was sonst? Warum arbeitest du nicht einfach mit Objekten statt Records? Den Pointer des Objektes kannst du auch in das Tag packen. Was passiert beim Connect (Zugriff auf User-DB) noch? Verschweigst du uns etwa Code ? :=) Heiko |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Ja, das sind die einzigen Lecks.
Das ist Heaptrc-Unit von Lazarus. Ich fand Records einfacher als Objekte. Solange ich keine Methoden benötige, verwende ich für gewöhnlich immer Records. Hier wäre ein Objekt vermutlich eleganter aufgrund der Initialisierung, aber ist halt Gewöhnungssache... Das Problem hängt aber auch vermutlich nicht damit zusammen, da ohne Abrufen von Daten aus der Datenbank alles glatt läuft. Der Sicherheit halber werde ich gleich aber mal eine Klasse bauen (und wenn sie mir gefällt, behalte ich sie :lol:). Nein, nein, ich verschweige keinen Code. :wink: Die entsprechende Stelle habe ich vollständig und ohne Änderung hier angegeben. Willst du denn noch einen anderen Teil sehen? Ich wüsste jetzt nicht, was noch relevant sein könnte... |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Hallo,
kannst auf nicht-SSL umstellen? Wie sieht das dann auch? Heiko |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Bin aufgehalten worden, kam daher erst jetzt zum Ausprobieren.
Die Umstellung auf Objekt statt Record hat, wie zu erwarten war, nichts gebracht. Zur Sicherheit wollte ich es aber ja mal ausprobieren. Vielleicht behalte ich es, auch wenn ich das ^ vermissen werde. (Das ganze Herumcasten ist nicht ganz so schön...) Zum Umstellen auf Nicht-SSL: Auch hier hat sich leider rein gar nichts geändert... Immer wieder kommen die gleichen Speicherlecks beim Senden der Query. Hat jemand von euch noch eine Idee? Oder sonst jemand aus der DP? Das muss doch zu lösen sein! |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Hallo,
wie sieht es hiermit aus? ![]() Interessant ist, ob sich die Lecks mit der Anzahl der Queries erhöhen, oder ob es immer 23 sind. Heiko |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Das hatte ich bei meiner Recherche auch schon gefunden, konnte aber nur die (absichtlichen) Speicherlecks von Indy entfernen. An dem Queryleck änderte es nichts
Die Anzahl der Speicherlecks nimmt mit der Anzahl der Querys stetig zu. Sie müssen also dabei entstehen. Wenn es an der Komponente liegt, frage ich mich, warum der Speichermanager mir sagt, es die Lecks kämen von den Indys… EDIT: Ich habe einmal testweise ein Programm ohne die Indys erstellt. Nur mein Container für die Komponenten (ohne IDContext). Dieser wurde erstellt, dieselbe Query ausgeführt (erfolgreich), das Containerobjekt zerstört und das Programm beendet: Die selben 23 Speicherlecks! Es muss also an SqlDB (oder meiner Query...) liegen! Weiß da jemand Rat? Oder kennt jemand eine Alternative? Ich hatte es zuerst mit Zeos versucht, da bekam ich aber die Querys irgendwie nicht hin... EDIT: Anmerkung: Die in dem Testprogramm auftretenden Speicherlecks haben nun leider keine Zeilen- oder Unitangaben mehr. |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Hat niemand mehr eine Idee?
|
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Zitat:
Ich habe noch nicht mit mySQL in der Form gearbeitet, aber schon mit anderen Datenbanken. Dort kenne ich es eigentlich so, dass NUR der Connection die Transaktion zugewiesen wird. Alle weiteren Elemente, die mit dieser Verbindung arbeiten, verwenden dann automatisch diese Transaction. Möglicherweise kommt dort etwas durcheinander. Ohne jetzt in die Tiefe zu gehen (also ungeprüft), sollte dies doch ausreichen:
Delphi-Quellcode:
A^.Verbindung.Transaction := A^.Transaktion;
A^.Anfrage.DataBase := A^.Verbindung; |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Zitat:
|
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
@Jasocul:
Sehr interessante Bemerkung. Ich habe es mal ausprobiert. Brachte aber leider keinen Erfolg. Dieselben 23 Speicherlecks...(wenngleich nunmehr ohne Verweis auf Indyunits.) Die Query funktioniert aber tadellos mit deinen Anweisungen. Die gegenseitige Zuweisung hatte ich aus diesem ![]() Zitat:
|
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Zitat:
![]() |
AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Das Problem ist gelöst! :-D
Heute morgen halb zehn ist das Update für CodeTyphon auf die Version 5.70 erschienen. Beim Durchstöbern bin ich auf einen Foreneintrag gestoßen, nachdem es einen Bug in den Free Pascal Sources gab, der in bestimmten Stringroutinen (verwendet von SqlDB...) ein Speicherleck erzeugt hat. Der ist mit der neuen version gefixt worden. Nach der Installation erhalte ich in meinem Programm nun ein schön sauberes "0 unfreed memory blocks" von Lazarus. Hurra! :lol: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz