AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken FreePascal Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage
Thema durchsuchen
Ansicht
Themen-Optionen

Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

Ein Thema von Benedikt Magnus · begonnen am 29. Feb 2016 · letzter Beitrag vom 3. Mär 2016
Antwort Antwort
Benedikt Magnus

Registriert seit: 6. Jul 2012
Ort: Bonn
190 Beiträge
 
FreePascal / Lazarus
 
#1

Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 29. Feb 2016, 15:29
Datenbank: MySQL • Version: 5.5 • Zugriff über: SqlDB
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:
type
  PFiRe = ^TFirstemRecord;
  TFirstemRecord = record
    Name: String;
    Spiel: String;
    Angemeldet: Boolean;
    Verbindung: TMySQL55Connection;
    Anfrage: TSQLQuery;
    Transaktion: TSQLTransaction;
    Context: TIdContext;
  end;
Der Zeiger auf dieses Record wird im Tag der Verbindung zum Client gespeichert. Das Ganze sieht dann so aus:
Delphi-Quellcode:
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;
Nun zu meinem eigentlichen Problem:

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:
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;
Lasse ich dieses Stück draußen, entstehen ebenfalls keine Speicherlecks. Und ich verstehe nicht warum.

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:
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
Und das Ganze 23 mal. Manchmal steht die letzte Zeile doppelt dort. Indyversion ist 10.6.2.20.
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
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.277 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 29. Feb 2016, 15:53
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:
AContext.Connection.Tag := Int64(New(PFiRe));

A^.Transaktion := TSQLTransaction.Create(nil);
A^.Anfrage := TSQLQuery.Create(nil);
Wo erfolgt denn die Freigabe dieser Klassen?

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
Heiko

Geändert von hoika (29. Feb 2016 um 16:04 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#3

AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 29. Feb 2016, 16:09
Delphi-Quellcode:
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;
Solchen Konstrukten traue nicht über den Weg
Delphi-Quellcode:
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;
versuch es mal so.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benedikt Magnus

Registriert seit: 6. Jul 2012
Ort: Bonn
190 Beiträge
 
FreePascal / Lazarus
 
#4

AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 29. Feb 2016, 17:22
Vielen Dank für eure Antworten!

Zitat von hoika:
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 .
Ich weiß. Die sind auch schon herausgefiltert und können hiermit, da hast du Recht, nichts zu tun haben.

Zitat von hoika:
Delphi-Quellcode:
AContext.Connection.Tag := Int64(New(PFiRe));

A^.Transaktion := TSQLTransaction.Create(nil);
A^.Anfrage := TSQLQuery.Create(nil);
Wo erfolgt denn die Freigabe dieser Klassen?
Die erfolgt im Disconnectereignis des TCP-Servers folgendermaßen:
Delphi-Quellcode:
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;
Funktioniert auch. Da werden keine Speicherlecks gemeldet.

Zitat von hoika:
Fehlendes Close (Zur Sicherheit);
Delphi-Quellcode:
with A^.Anfrage do
begin
  Close;
  SQL.Text := 'SELECT passwort FROM nutzer WHERE name = :NAME';
Habe ich ausprobiert. Ändert aber leider nichts.


Zitat von p80286:
Solchen Konstrukten traue nicht über den Weg
markieren
Delphi-Quellcode:
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;
versuch es mal so.
Auch das hat leider nichts geändert (auch wenn es so schön vielversprechend aussah...). Ich bekomme die gleichen Speicherleckmeldungen...
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.277 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 29. Feb 2016, 18:21
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
Heiko

Geändert von hoika (29. Feb 2016 um 18:33 Uhr)
  Mit Zitat antworten Zitat
Benedikt Magnus

Registriert seit: 6. Jul 2012
Ort: Bonn
190 Beiträge
 
FreePascal / Lazarus
 
#6

AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 29. Feb 2016, 18:46
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 ).

Nein, nein, ich verschweige keinen Code.
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...
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.277 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 29. Feb 2016, 18:55
Hallo,
kannst auf nicht-SSL umstellen?
Wie sieht das dann auch?


Heiko
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von Jasocul
Jasocul

Registriert seit: 22. Sep 2004
Ort: Delmenhorst
1.368 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Speicherleck mit SqlDB (und Indy-TCP-Server) bei Datenbankabfrage

  Alt 3. Mär 2016, 08:30
Delphi-Quellcode:
  //Zuweisungen:
  A^.Verbindung.Transaction := A^.Transaktion;
  A^.Transaktion.DataBase := A^.Verbindung;
  A^.Anfrage.DataBase := A^.Verbindung;
  A^.Anfrage.Transaction := A^.Transaktion;
end;
Das kommt mir verdächtig vor.
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;
Peter
  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 20:31 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