BUG: Memory Leak in OLE DB Provider for SQL Server When It Is Loaded and Unloaded Multiple Times (294168)



The information in this article applies to:

  • Microsoft Data Access Components 2.5
  • Microsoft Data Access Components 2.6

This article was previously published under Q294168

SYMPTOMS

You may see a memory leak when repeatedly loading and unloading the Microsoft OLE DB provider for SQL Server (SQLOLEDB) and connecting to a Microsoft SQL Server database. You may see the same behavior when using the Microsoft OLE DB provider for ODBC drivers (MSDASQL) with the SQL Server ODBC driver.

CAUSE

This is caused by a slight memory leak in the OLE DB implementation support routines (Msdatl2.dll or Msdatl3.dll).

RESOLUTION

To work around this problem, keep a global connection alive or have the COM library initialized in the main thread.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article. This problem was corrected in MDAC 2.7, and MDAC 2.5 Service Pack 3 (SP3).
There is also a hotfix available for this problem. For additional information about this hotfix, click the article number below to view the article in the Microsoft Knowledge Base:

312575 FIX: Virtual Memory Leak with Large Number of Concurrently Open Recordsets

MORE INFORMATION

Steps to Reproduce the Behavior

  1. Create a Win32 console application in Microsoft Visual C++ 6.0 using the following code:
    #include <stdio.h>
    #include <tchar.h>
    
    #import <msado15.dll> no_namespace rename("EOF", "EndOfFile")
    
    void TestFunction()
    {	
    	// Initialize COM library.
    	CoInitialize(NULL);
    
    	try
    	{
           	   _ConnectionPtr pConn(__uuidof(Connection));
    	   _CommandPtr pCmd(__uuidof(Command));
    	   _RecordsetPtr pRs;
    
     	   // Open the database connection.
                _bstr_t strCnn("Provider=SQLOLEDB;Data Source=<datasource>;Initial Catalog=pubs;User ID=<uid>;Password=<pwd>;");
    	   pConn->Open(strCnn, "", "", -1);
    
       	   // Set command object's properties.
    	   pCmd->ActiveConnection = pConn;
    	   pCmd->CommandText = "select * from authors";
    	   pCmd->CommandType = adCmdText;
    		
    	   // Execute the SQL statement.
    	   pRs = pCmd->Execute(NULL,NULL,adCmdText);
    	   pRs->MoveFirst();
    
         	   pRs->Close();
    	   pConn->Close();
    	}
    	catch (_com_error &e)
    	{
    	   _tprintf("Error\n");
    	   _tprintf("\tCode = %08lx\n", _T(e.Error()));
    	   _tprintf("\tCode meaning = %s\n", _T(e.ErrorMessage()));
    	   _tprintf("\tSource = %s\n", _T((LPCSTR) e.Source()));
    	   _tprintf("\tDescription = %s\n", _T((LPCSTR) e.Description()));
    	}
    	
    	// Uninitialise COM library.
    	CoUninitialize();
    }
    
    int main()
    {
       //CoInitialize(NULL);
    
       // Loop for testing.
       for (int i = 0; i < 1000; i++)
       {
     	TestFunction();
    	_tprintf("%d ", i);
    	Sleep(100); // Pause for some time.
       };
    
       //CoUninitialize();
       return 0;
    }
    					
  2. Modify the connection string to suit your environment. Run the application, and use Performance Monitor to watch the private bytes of the process. You will see the memory leak.
  3. Uncomment the initialization calls in the main function and the leak will disappear.

Modification Type:MajorLast Reviewed:4/6/2004
Keywords:kbbug kbfix KB294168