TADOConnection verursacht Memory Leak



  • Hallo,

    seit einiger Zeit bin ich auf der Suche nach einem Fehler in Verbindung mit der TADOConnection Komponente.
    Ich benutze diese um Verbindung zu einer Datenbank zu bekommen. Dazu habe ich eine Funktion, welche eine
    Verbindung zu einer Datenbank herstellen soll. Wenn die Verbindung hergestellt werden kann ist alles OK.
    Falls aber nicht, weil z.B. die MDB-Datei fehlt oder der Netzwerkserver nicht antwortet, bekomme ich beim
    Beenden des Programms laut MadExcept einen MemoryLeak.

    Folgende Funktionen werden dabei verwendet:
    DataModul Header Datei:

    //---------------------------------------------------------------------------
    
    #ifndef DataModulH
    #define DataModulH
    //---------------------------------------------------------------------------
    #include <System.Classes.hpp>
    #include <Data.DB.hpp>
    #include <Data.Win.ADODB.hpp>
    #include <Xml.Win.msxmldom.hpp>
    #include <Xml.XMLDoc.hpp>
    #include <Xml.xmldom.hpp>
    #include <Xml.XMLIntf.hpp>
    
    //---------------------------------------------------------------------------
    class TDataModule1 : public TDataModule {
    __published: // Von der IDE verwaltete Komponenten
    	TADOConnection *actDataService;
    	TADODataSet *adsDataService;
    	TADOQuery *aqrDataService;
    private:                            // Benutzer-Deklarationen
    
    	void SetupDatabaseComponents(); // Setup the Database Components for internal use
    public:                             // Benutzer-Deklarationen
    	__fastcall TDataModule1(TComponent* Owner);
    	__fastcall ~TDataModule1();
    	bool ConnectDatabase(const UnicodeString sServerType, const UnicodeString sServerName,
    		const UnicodeString sUserName, const UnicodeString sPassword, const UnicodeString sDatabase);
    };
    
    //---------------------------------------------------------------------------
    extern PACKAGE TDataModule1 *DataModule1;
    //---------------------------------------------------------------------------
    #endif
    

    DataModul CPP-Datei:

    //---------------------------------------------------------------------------
    
    #pragma hdrstop
    
    #include "DataModul.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma classgroup "System.Classes.TPersistent"
    #pragma resource "*.dfm"
    TDataModule1 *DataModule1;
    
    void TDataModule1::SetupDatabaseComponents() {
    	// Einstellungen fuer die Datenbank Verbindungs Komponente
    	actDataService->Close();
    	actDataService->ConnectionString = "";
    	actDataService->CursorLocation = clUseClient;
    	actDataService->KeepConnection = true;
    	actDataService->LoginPrompt = false;
    	// Einstellungen fuer die Datenbank Query Komponente
    	aqrDataService->Active = false;
    	aqrDataService->SQL->Clear();
    	aqrDataService->CursorLocation = clUseClient;
    	aqrDataService->ParamCheck = false;
    	aqrDataService->Connection = actDataService;
    	// Einstellungen fuer die Datenbank DataSet Komponente
    	adsDataService->Active = false;
    	adsDataService->CursorLocation = clUseClient;
    	adsDataService->ParamCheck = false;
    	adsDataService->Connection = actDataService;
    }
    
    bool TDataModule1::ConnectDatabase(const UnicodeString sServerType,
    	const UnicodeString sServerName, const UnicodeString sUserName, const UnicodeString sPassword,
    	const UnicodeString sDatabase) {
    
    	bool bResult = true;
    
    	// besteht bereits eine Verbindung zu einer/einem Datenbank/Server
    	if (actDataService->Connected) {
    		// ja, diese dann schließen
    		actDataService->Close();
    	}
    
    	if (sServerType.LowerCase().Pos("(*.mdb)")) {
    		// Verbindungsdaten fuer eine lokale Access2000 kompatible Datenbank
    		actDataService->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=TPOlcldb.mdb";
    		actDataService->Provider = "Microsoft.Jet.OLEDB.4.0";
    	}
    	else if (sServerType.LowerCase().Pos("mysql")) {
    		// Verbindungsdaten fuer einen MySQL Netzwerk Datenbank-Server
    		actDataService->ConnectionString = "DRIVER={" + sServerType + "};SERVER=" +
    			sServerName + ";Network=DBMSSOCN;" + "DATABASE=" + sDatabase + ";UID=" + sUserName +
    			";PWD=" + sPassword + ";OPTION=3";
    		actDataService->Provider = "MSDASQL";
    	}
    	else if (sServerType.LowerCase().Pos("sql server")) {
    		// Verbindungsdaten fuer einen MS-SQL(2005/2008) Netzwerk Datenbank-Server
    		actDataService->ConnectionString = "Driver={" + sServerType + "};Server=" +
    			sServerName + ";Network=DBMSSOCN;" + "Database=" + sDatabase + ";User ID=" + sUserName +
    			";Password=" + sPassword;
    		actDataService->Provider = "SQLNCLI10";
    	}
    	else {
    		// kein gueltiger Server Treiber angegeben
    		return (false);
    	}
    	try {
    		// und mit den neuen Verbindungsdaten wieder oeffnen
    		actDataService->Open();
    	}
    	catch (...) {
    		actDataService->Close();
    		bResult = false;
    	}
    	return (bResult);
    }
    
    //---------------------------------------------------------------------------
    __fastcall TDataModule1::TDataModule1(TComponent* Owner) : TDataModule(Owner) {
    	SetupDatabaseComponents();
    }
    

    sowie Hauptprogramm Header-Datei:

    // ---------------------------------------------------------------------------
    
    #ifndef TestMainFormH
    #define TestMainFormH
    // ---------------------------------------------------------------------------
    #include <System.Classes.hpp>
    #include <Vcl.Controls.hpp>
    #include <Vcl.StdCtrls.hpp>
    #include <Vcl.Forms.hpp>
    #include <Vcl.ComCtrls.hpp>
    
    // --------------------------------------------------------------------------
    class TForm1 : public TForm {
    __published: // Von der IDE verwaltete Komponenten
    	TButton *Button1;
    	TButton *Button2;
    	TButton *Button3;
    	void __fastcall Button1Click(TObject *Sender);
    	void __fastcall Button2Click(TObject *Sender);
    	void __fastcall Button3Click(TObject *Sender);
    
    private: // Anwender-Deklarationen
    
    		public : // Anwender-Deklarationen
    
    	__fastcall TForm1(TComponent* Owner);
    };
    
    // ---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    // ---------------------------------------------------------------------------
    #endif
    

    und Hautpprogramm CPP-Datei:

    // ---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "TestMainForm.h"
    #include "DataModul.h"
    
    // ---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    
    TForm1 *Form1;
    
    // ---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
    
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Button1Click(TObject *Sender) {
    	try {
    		DataModule1 = new TDataModule1(NULL);
    	}
    	catch (...) {
    		//
    	}
    }
    
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender) {
    	try {
    		delete DataModule1;
    		DataModule1 = NULL;
    	}
    	catch (...) {
    		//
    	}
    }
    
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button3Click(TObject *Sender) {
    	// pruefe das Vorhandensein einer lokalen Datenbank
    	if (!DataModule1->ConnectDatabase("Microsoft Access Driver (*.mdb)", "", "", "", "")) {
    		// es ist keine gueltige lokale Datenbank vorhanden
    		MessageDlg("MSG_LOCAL_DATABASE_MISSING", mtInformation, TMsgDlgButtons() << mbOK, 0);
    	}
    }
    //---------------------------------------------------------------------------
    

    und zum Schluß der Memory-Leak Report von MadExcept:

    allocation number: 2308
    program up time: 5,04 s
    type: GetMem
    address: $bddf3f0
    size: 28
    access rights: read/write
    
    main thread ($a9c):
    671ca339 madExcept32.dll   madExceptDbg     1453 GetMemCallback
    0cd01c4a CG32.DLL                                __cg_malloc
    0cd03050 CG32.DLL                                __cg_new
    32c70498 CC32120MT.DLL                           ___VCL_add_EH
    32c7635a CC32120MT.DLL                           ____ExceptionHandler
    00406f68 UniversalTest.exe                       __ExceptionHandler
    7751012e ntdll.dll                               KiUserExceptionDispatcher
    50fcbd1f adortl160.bpl     Data.Win.ADODB   1647 TADOConnection.DoConnect
    508ee0bd dbrtl160.bpl      Data.DB          3159 TCustomConnection.SetConnected
    00404a25 UniversalTest.exe DataModul.cpp      88 TDataModule1.ConnectDatabase
    00405552 UniversalTest.exe TestMainForm.cpp   47 TForm1.Button3Click
    50332d6f vcl160.bpl        Vcl                   Controls.TControl.Click
    50337163 vcl160.bpl        Vcl                   Controls.TWinControl.WndProc
    50356cf0 vcl160.bpl        Vcl                   Stdctrls.TButtonControl.WndProc
    50337163 vcl160.bpl        Vcl                   Controls.TWinControl.WndProc
    50449405 vcl160.bpl        Vcl                   Forms.TCustomForm.WndProc
    503367b8 vcl160.bpl        Vcl                   Controls.TWinControl.MainWndProc
    752096c0 USER32.dll                              SendMessageW
    75210d48 USER32.dll                              CallWindowProcW
    50337260 vcl160.bpl        Vcl                   Controls.TWinControl.DefaultHandler
    50337163 vcl160.bpl        Vcl                   Controls.TWinControl.WndProc
    50356cf0 vcl160.bpl        Vcl                   Stdctrls.TButtonControl.WndProc
    75207885 USER32.dll                              DispatchMessageW
    504524ef vcl160.bpl        Vcl                   Forms.TApplication.ProcessMessage
    
    memory dump: 
    0bddf3f0  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
    0bddf400  00 00 00 00 00 00 00 00 - 00 00 00 00              ............
    

    Das ist ein wirklich auf das notwendigste zusammengestrichenes Testprojekt, mit welchem sich der Fehler
    aber jederzeit reproduzieren lässt. Wäre über Hilfe sehr dankbar.

    Grüße Netzschleicher



  • Nachtrag:

    Ich habe obigen Code im C++Builder XE2 geschrieben. Dort tritt der Fehler auch auf. Auch wenn ich die ADOConnection direkt in dem eigentlichen Fenster verwende ohne das Datenmodul.
    Zum Testen habe ich dieses Szenario nun auch im RAD Studio 2007 nachvollzogen. Dort tritt dieser Fehler nicht auf.
    Ist das jetzt ein kleiner Bug im XE2 oder hat MadExcept mit dem XE2 probleme?
    Wäre nett wenn mir da jemand weiterhelfen könnte.

    Grüße



  • Hallo an alle,

    ich möchte mit aller Höflichkeit mal nachfragen ob zu meinem Problem keiner eine Idee oder Lösungsvorschlag hat. Vielleicht mache ich ja auch bei der 'try - catch' Konstruktion einen Fehler? Wie schon beschrieben tritt der Fehler beim Beenden nur unter C++ XE2 auf, nicht unter C++ 2007. Falls es an dem MadExcept liegen sollte, dann kann ich damit auch leben. Falls das aber doch wieder so eine Verschlimmbesserung im C++ XE2 ist, spiele ich mit dem Gedanken den C++ XE2 nicht mehr zu nutzen und bleibe lieber beim C++ 2007. Evtl. werd ich mich dann auch vom C++ XE2 trennen.

    Grüße Netzschleicher



  • Hi,
    hab mir deinen Code jetzt mal durchgelesen und habe nichts sehen können, was auf ein MemLeak hinweisst.
    Interessant wären evtl. noch dein Kon-/Destruktor von DataModule1, sowie die Klasse TDataModule von der du ja TDataModule1 ableitest, vielleicht ist da was zu finden.

    mfg



  • Ich glaube nicht das es an dem Datenmodul liegt. Wie ich schon angedeutet habe, tritt der Fehler auch auf wenn die ADO-Komponenten
    direkt in der Form liegen und dort auch aufgerufen werden. Ich vermute eher das bei den Erweiterungen der VCL im Builder XE2
    irgendwo ein kleiner Fehler sich eingeschlichen hat. Was natürlich sehr böse wäre.
    Wie schon geschrieben, im RAD-Studio 2007 läuft das alles ohne einen einzigen Fehler.


Anmelden zum Antworten