![]() |
ADO Memoryleak / Speicherleck ?!
Hey,
ich habe eine Client/Server-Serviceanwendung programmiert und soweit funktioniert auch alles. Bis auf einen einzigen Punkt. Und zwar sobald eine Datenbank Verbindung innerhalb eines Threads ins Spiel kommt steigt mein Arbeitsspeicherverbrauch der .exe mit jeder Anfrage. Ich habe es schon soweit dezimiert das lediglich eine ADOConnection instanziiert wird, ein ConnectionString übergeben wird, danach die Verbindung geöffnet und anschließend (ohne ein SQL Command auszuführen !) wieder geschlossen & ge-FreeAndNil't wird. Dennoch steigt der Arbeitsspeicherverbrauch mit jedem Durchlauf dieses Vorganges. Ich weis so langsam nicht mehr wie ich das Unterbinden kann. Leider bin ich auch auf die ADO-Geschichte angewiesen da wir eine ältere SAP-MaxDb Datenbank benutzen (müssen). Quellcode: Connect Funktion:
Code:
Disconnect Funktion:
function TdatabaseInfo.Connect : boolean;
begin try if fConnectionString <> '' then begin ADOConnection.ConnectionString := fConnectionString; // Übergibt Connection String end else begin Result := false; nxLogging.Logger.error('TdatabaseInfo.Connect', 'connection string empty'); Exit; end; ADOConnection.Open; if ADOConnection.Connected then begin Result := true; end; except on e : exception do begin Result := false; nxLogging.Logger.error('TdatabaseInfo.Connect', 'error during ADO connect: ' + E.Message); end; end; end;
Code:
Ist jetzt nicht schön und auch nur fix "zusammengehackt", aber läuft, bis auf das Memoryleak. :idea:
function TdatabaseInfo.Disconnect : boolean;
begin try ADOConnection.Close; ADOConnection.Connected := false; finally Result := true; end; end; Jemand ne Ahnung woran das liegt oder wie sich das Unterbinden lässt ? Beste Grüße |
AW: ADO Memoryleak / Speicherleck ?!
Moin...:P
Zeige mal den kompletten Thread incl. der Instanzierung der ADO. |
AW: ADO Memoryleak / Speicherleck ?!
Hey, Sorry ich hab mich bei der Erklärung nicht ordentlich ausgedrückt. :-D
Also ich habe eine Klasse "tdatabaseinfo" abgeleitet von TDataModule inkl. einer Form wo die ADOConnection als Komponente drauf liegt. Diese Klasse erzeuge ich im execute-Teil des Threads und gebe sie auch mit FreeAndNil wieder frei. Das passiert innerhalb des Threads in einer "while not terminated"-Schleife, mit sleep dazwischen. Quellcode: Thread create:
Code:
Thread execute:
constructor TWorkerThread.create(aCreateSuspended: Boolean; aConnStr : String; aHost : String; aPort : Word; aSleepTime : Integer);
begin inherited create(aCreateSuspended); FreeOnTerminate := false; fConnStr := aConnStr; fSleepTime := aSleepTime; fHost := aHost; fPort := aPort; fConnected := false; fTcpClient := TIdTCPClient.Create(nil); fTcpClient.Host := aHost; fTcpClient.Port := aPort; fTcpClient.ConnectTimeout := 3000; fTcpClient.ReadTimeout := fSleepTime; MsgCenter := TMsgCenter.Create(fConnStr); ErrCnt := 0; nxLogging.Logger.info('TWorkerThread.create', 'created..'); end;
Code:
databaseInfo.Connect:
procedure TWorkerThread.execute;
var ServerMsg : String; begin inherited; try fTcpClient.Connect; fConnected := true; nxLogging.Logger.trace('TWorkerThread.execute', 'tcp connected'); except on e: Exception do begin nxLogging.Logger.error('TWorkerThread.execute', e.Message); end; end; while not self.Terminated do begin try if fTcpClient.Connected then begin databaseInfo := TdatabaseInfo.Create(nil); databaseInfo.ConnectionString := fConnectionString; if not databaseInfo.isConnected then begin databaseInfo.Connect; end; //do stuff, auskommentiert.. databaseInfo.Disconnect; FreeAndNil(databaseInfo); end else begin nxLogging.Logger.error('TWorkerThread.execute', 'tcp connection failed'); Reconnect; end; except on E: Exception do begin nxLogging.Logger.error('TWorkerThread.execute', 'error: ' + e.Message); Reconnect; end; end; sleep(fSleepTime); end; fTcpClient.Disconnect; nxLogging.Logger.trace('TWorkerThread.execute', 'tcp disconnected'); end;
Code:
databaseinfo.Disconnect:
function TdatabaseInfo.Connect : boolean;
begin try if fConnectionString <> '' then begin ADOConnection.ConnectionString := fConnectionString; // Übergibt Connection String end else begin Result := false; nxLogging.Logger.error('TdatabaseInfo.Connect', 'connection string empty'); Exit; end; ADOConnection.Open; if ADOConnection.Connected then begin Result := true; end; except on e : exception do begin Result := false; nxLogging.Logger.error('TdatabaseInfo.Connect', 'error during ADO connect: ' + E.Message); end; end; end;
Code:
function TdatabaseInfo.Disconnect : boolean;
begin try ADOConnection.Close; ADOConnection.Connected := false; finally Result := true; end; end; Jedesmal wenn der Thread durch die while-Schleife rennt steigt der Arbeitsspeicher um ein paar hundert Kilobyte. :?: |
AW: ADO Memoryleak / Speicherleck ?!
Moin...:P
Delphi-Quellcode:
* Form oder Datenmodul?databaseInfo := TdatabaseInfo.Create(nil); * ADOConnection auf der Form? * Was macht diese Form/Datamodule?
Delphi-Quellcode:
* Irgendwelche Zugriffe auf die VCL?//do stuff, auskommentiert.. * Syncronize Nachtrag: Zitat:
PS: Ich muß dann mal Pause machen. Vieleicht kann dir das jemand in der Zwischenzeit erklären...8-) |
AW: ADO Memoryleak / Speicherleck ?!
Wo ist denn das
Delphi-Quellcode:
und das
ADOConnection.Create
Delphi-Quellcode:
?
ADOConnection.Free
Gruß K-H Vergesst es , ich hab da wohl einiges übersehen ! |
AW: ADO Memoryleak / Speicherleck ?!
Zitat:
|
AW: ADO Memoryleak / Speicherleck ?!
Statt zu raten wäre doch eigentlich der erste Schritt zu schauen was sich hier stapelt.
![]() ![]() Dann sollte man den Code doch ein einziges mal ausführen und schauen was dann an Speicherlecks herauskommt. Wenn man dann noch die Deluxe-Version des Speichermanagers einsetzt [1] kann man sich sogar den gesamten Stack anzeigen lassen was wann erstellt und nicht wieder freigegeben wurde. [1] ![]() |
AW: ADO Memoryleak / Speicherleck ?!
Nur zur Erinnerung: Die ADOConnection ist NICHT threadsafe. Jeder Thread benötigt eine eigene Connection. Ist IIRC auch bei FireDAC so.
|
AW: ADO Memoryleak / Speicherleck ?!
Es gibt nur diesen einen Thread, davon gibt es keine weiteren Instanzen, deshalb musste ich mir an dieser Stelle über Multithreading keine Gedanken machen.
Tdatabaseinfo ist eine TDataModule abgeleitete Klasse, die VCL benutze ich nicht da es ein reiner Windows Service ist :) Momentan kann ich mir nur noch Erklären das der Fehler in der ADOConnection selbst liegt, da ja sonst keinerlei Aktionen mit dieser Connection getätigt werden außer die Verbindung zu öffnen und wieder zu schließen. RE: Habe das ganze jetzt nochmal in ein eigenes Projekt ausgelagt um in ruhe daran rumzuexperimentieren. Aufbau: habe eine VLC Form mit start Button, der Button startet einen Thread welcher wiederrum in der Execute Methode eine TADOConnection created, connected, disconnected, freeAndNil`t. Ergebnis = gleiches Problem :-/ Reportmemoryleaksonshutdown bringt keinerlei Meldung. Habe es im FormShow auf true gesetzt. ?! Code:
Code:
unit Unit8;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, ActiveX, Data.Win.ADODB; type TWorkerThread = class(TThread) private txt : String; ADOConnection : TADOConnection; procedure Sync; public constructor create; destructor destroy; override; procedure execute; override; end; //-------------------------------------------- TForm8 = class(TForm) btnStart : TButton; mmo : TMemo; procedure btnStartClick(Sender: TObject); procedure FormShow(Sender: TObject); private fStarted : Boolean; fThread : TWorkerThread; public { Public-Deklarationen } end; //-------------------------------------------- var Form8: TForm8; implementation {$R *.dfm} procedure TForm8.FormShow(Sender: TObject); begin fStarted := false; mmo.Clear; ReportMemoryLeaksOnShutdown := true; end; procedure TForm8.btnStartClick(Sender: TObject); begin if fStarted then begin fThread.Terminate; fThread.WaitFor; FreeAndNil(fThread); fStarted := false; btnStart.Caption := 'Start'; end else begin fThread := TWorkerThread.Create(); fThread.start; fStarted := true; btnStart.Caption := 'Stop'; end; end; // TWorkerThread ------------------------- constructor TWorkerThread.create; begin inherited create(true); FreeOnTerminate := false; txt := 'created'; Synchronize(Sync); end; destructor TWorkerThread.destroy; begin txt := 'destroyed'; Synchronize(Sync); inherited; end; procedure TWorkerThread.execute; begin inherited; try CoInitialize(nil); try ADOConnection := TADOConnection.Create(nil); ADOConnection.ConnectionString := 'Provider=MSDASQL.1;Password=PASSWORD;Persist Security Info=True;User ID=ADMIN;Data Source=DB'; ADOConnection.Open; finally sleep(1000); ADOConnection.Close; FreeAndNil(ADOConnection); CoUninitialize; end; except on e: Exception do begin txt := e.Message; Synchronize(Sync); end; end; end; procedure TWorkerThread.Sync; begin Form8.mmo.Lines.Add(DateTimeToStr(now) + ' | ' + txt) end; end. |
AW: ADO Memoryleak / Speicherleck ?!
keiner eine Idee ?!
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:08 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