EDN Admin
Well-known member
Iâve been looking for the root cause of memory leaks in my code and keep coming back to ADO. The code is acting as if there was some sort of reference counting issue within the ADO components. Iâve been over this code dozens of times over the
last few days and was not able to locate a reference counting issue.
OS: Windows Server 2008 R2, all updates applied as of 11/30/2011
MSADO15.DLL version 6.1.7600.16688
MSADCE.DLL version 6.1.7600.20595
I have found a number of hot fixes for memory leaks in ADO, but have not found a hot fix (or combination of) that resolves all of my leaks.
KB978042 (http://support.microsoft.com/kb/978042) You use the Microsoft ActiveX Data Objects Library (Msado15.dll) to access the ConnectionString property of the ADODB.Connection object.
My application does not retrieve the ADO connection string (so the hot fix kb978042 should not apply).
KB978155(http://support.microsoft.com/kb/978155) You have an SQL table that contains an identity column. You start an application that uses a Microsoft ActiveX Data Objects (ADO) client-side Recordset object to access the SQL database. This application calls
the UpdateBatch method to insert several rows into the table.
All of the items in KB978155 applied to my application and I was experiencing a leak when UpdateBatch() was called until I applied this hotfix.
The following test code demonstrates the leaks Iâm seeing.
When the function was executed 10,000 times private bytes for the process went from 1,839,104 bytes to 2,920,448.
HRESULT CADO_LeakDlg::OpenRSWithCommand( )
{
<span style="white-spacere USES_CONVERSION;
<span style="white-spacere HRESULT hr = S_OK;
<span style="white-spacere CComPtr<ADO::ADOConnection><span style="white-spacere
spConnection;
<span style="white-spacere CComPtr<ADOCommand><span style="white-spacere
spADOCmd;
<span style="white-spacere CComPtr<ADORecordset><span style="white-spacere
spRS;
<span style="white-spacere BSTR bstrConnectionString<span style="white-spacere
= ::SysAllocString( WSZ_CONNECTION_STRING );
<span style="white-spacere BSTR bstrUser<span style="white-spacere
= ::SysAllocString( WSZ_USER_STRING );
<span style="white-spacere BSTR bstrPassword<span style="white-spacere
= ::SysAllocString( WSZ_PWD_STRING );
<span style="white-spacere try
<span style="white-spacere {
<span style="white-spacere // Open the ADO Connection
<span style="white-spacere hr = OpenConnection( spConnection, bstrConnectionString, bstrUser, bstrPassword );
<span style="white-spacere if(spConnection)
<span style="white-spacere {
<span style="white-spacere if(SUCCEEDED(hr))
<span style="white-spacere {
<span style="white-spacere // Create the ADO Command object
<span style="white-spacere hr = CoCreateInstance(CLSID_CADOCommand, NULL,
<span style="white-spacere CLSCTX_INPROC_SERVER, IID_IADOCommand, (LPVOID *)&spADOCmd);
<span style="white-spacere _bstr_t stored_proc = _T("MySchema.MyStoredProc");
<span style="white-spacere // Set the active connection
<span style="white-spacere hr = spADOCmd->putref_ActiveConnection( spConnection );
<span style="white-spacere hr = spADOCmd->put_CommandText(stored_proc);
<span style="white-spacere hr = spADOCmd->put_CommandType(adCmdStoredProc);
<span style="white-spacere // Create the parameters for my stored procedure
<span style="white-spacere _variant_t vFamilyID<span style="white-spacere
= 1L;
<span style="white-spacere _variant_t vUniqueID<span style="white-spacere
= 2L;
<span style="white-spacere _variant_t vMemberID<span style="white-spacere
= 2L;
<span style="white-spacere
<span style="white-spacere _variant_t vMemberIID(L"{F4DDF1B8-BB56-4293-873F-5D1B6357C30C}");
<span style="white-spacere CComPtr<ADOParameter> spParam1 = NULL;
<span style="white-spacere CComPtr<ADOParameter> spParam2 = NULL;
<span style="white-spacere CComPtr<ADOParameter> spParam3 = NULL;
<span style="white-spacere CComPtr<ADOParameter> spParam4 = NULL;
<span style="white-spacere CComPtr<ADOParameters> spParams = NULL;
<span style="white-spacere
<span style="white-spacere hr = spADOCmd->get_Parameters( &spParams );
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("FamilyID")), adInteger,
<span style="white-spacere adParamInput, 4, vFamilyID, &spParam1);
<span style="white-spacere hr = spParams->Append(spParam1);
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("UniqueID")), adInteger,
<span style="white-spacere adParamInput, 4, vUniqueID, &spParam2);
<span style="white-spacere hr = spParams->Append(spParam2);
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("MemberIID")), adGUID,
<span style="white-spacere adParamInput, 255, vMemberIID, &spParam3);
<span style="white-spacere hr = spParams->Append(spParam3);
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("MemberID")), adInteger,
<span style="white-spacere adParamInput, 4, vMemberID, &spParam4);
<span style="white-spacere hr = spParams->Append(spParam4);
<span style="white-spacere // Create the ADO record set object
<span style="white-spacere CComPtr<ADORecordset> spRS;
<span style="white-spacere hr = CoCreateInstance(CLSID_CADORecordset, NULL, CLSCTX_INPROC_SERVER,
<span style="white-spacere IID_IADORecordset, (LPVOID *)&spRS);
<span style="white-spacere _variant_t vtSource = spADOCmd;
<span style="white-spacere _variant_t vNull;<span style="white-spacere
<span style="white-spacere V_VT(&vNull) = VT_ERROR;
<span style="white-spacere V_ERROR(&vNull) = DISP_E_PARAMNOTFOUND;
<span style="white-spacere hr = spRS->put_CursorLocation( adUseClient );
<span style="white-spacere // Open the recordset with the ADO command object (passed in as vtSource)
<span style="white-spacere hr = spRS->Open( vtSource, vNull, adOpenKeyset, adLockOptimistic,
<span style="white-spacere adCmdStoredProc );
<span style="white-spacere if(SUCCEEDED(hr))
<span style="white-spacere {
<span style="white-spacere VARIANT_BOOL<span style="white-spacere
vbEOF;
<span style="white-spacere hr = spRS->get_EOF(&vbEOF);
<span style="white-spacere }
<span style="white-spacere // Should not *have* to do this, as the smart pointers should release
<span style="white-spacere // the object when it goes out of scope.
<span style="white-spacere // Setting to NULL Should release the last reference to the ADO paramx object.
<span style="white-spacere spParam1 = NULL;
<span style="white-spacere spParam2 = NULL;
<span style="white-spacere spParam3 = NULL;
<span style="white-spacere spParam4 = NULL;
<span style="white-spacere spParams = NULL;
<span style="white-spacere // Setting to NULL Should release the last reference to the ADO params object.
<span style="white-spacere spParams = NULL;
<span style="white-spacere // Setting to NULL Should release the last reference to the ADO command object.
<span style="white-spacere spADOCmd = NULL;
<span style="white-spacere spRS->Close();
<span style="white-spacere spRS = NULL;
<span style="white-spacere spConnection->Close();<span style="white-spacere
// Close the connection
<span style="white-spacere }
<span style="white-spacere spConnection = NULL;<span style="white-spacere
// Release the connection COM object
<span style="white-spacere }
<span style="white-spacere }
<span style="white-spacere catch(...)
<span style="white-spacere {
<span style="white-spacere }
<span style="white-spacere if( bstrConnectionString )
<span style="white-spacere ::SysFreeString( bstrConnectionString );
<span style="white-spacere bstrConnectionString = NULL;
<span style="white-spacere if( bstrUser )
<span style="white-spacere ::SysFreeString( bstrUser );
<span style="white-spacere bstrUser = NULL;
<span style="white-spacere if( bstrPassword )
<span style="white-spacere ::SysFreeString( bstrPassword );
<span style="white-spacere bstrPassword = NULL;
<span style="white-spacere return hr;
}
HRESULT CADO_LeakDlg::OpenConnection( CComPtr<ADO::ADOConnection> &spConnection,
BSTR bstrConnectionString, BSTR bstrUser, BSTR bstrPassword )
{
<span style="white-spacere HRESULT hr = S_OK;
<span style="white-spacere hr = CoCreateInstance(CLSID_CADOConnection, NULL,
<span style="white-spacere CLSCTX_INPROC_SERVER, IID_IADOConnection, (void **)&spConnection);
<span style="white-spacere if(FAILED(hr))
<span style="white-spacere return hr;<span style="white-spacere
// Failed to create the connection object
<span style="white-spacere hr = spConnection->Open( bstrConnectionString, bstrUser, bstrPassword, adOpenUnspecified );
<span style="white-spacere return hr;
}
<br/>
View the full article
last few days and was not able to locate a reference counting issue.
OS: Windows Server 2008 R2, all updates applied as of 11/30/2011
MSADO15.DLL version 6.1.7600.16688
MSADCE.DLL version 6.1.7600.20595
I have found a number of hot fixes for memory leaks in ADO, but have not found a hot fix (or combination of) that resolves all of my leaks.
KB978042 (http://support.microsoft.com/kb/978042) You use the Microsoft ActiveX Data Objects Library (Msado15.dll) to access the ConnectionString property of the ADODB.Connection object.
My application does not retrieve the ADO connection string (so the hot fix kb978042 should not apply).
KB978155(http://support.microsoft.com/kb/978155) You have an SQL table that contains an identity column. You start an application that uses a Microsoft ActiveX Data Objects (ADO) client-side Recordset object to access the SQL database. This application calls
the UpdateBatch method to insert several rows into the table.
All of the items in KB978155 applied to my application and I was experiencing a leak when UpdateBatch() was called until I applied this hotfix.
The following test code demonstrates the leaks Iâm seeing.
When the function was executed 10,000 times private bytes for the process went from 1,839,104 bytes to 2,920,448.
HRESULT CADO_LeakDlg::OpenRSWithCommand( )
{
<span style="white-spacere USES_CONVERSION;
<span style="white-spacere HRESULT hr = S_OK;
<span style="white-spacere CComPtr<ADO::ADOConnection><span style="white-spacere
spConnection;
<span style="white-spacere CComPtr<ADOCommand><span style="white-spacere
spADOCmd;
<span style="white-spacere CComPtr<ADORecordset><span style="white-spacere
spRS;
<span style="white-spacere BSTR bstrConnectionString<span style="white-spacere
= ::SysAllocString( WSZ_CONNECTION_STRING );
<span style="white-spacere BSTR bstrUser<span style="white-spacere
= ::SysAllocString( WSZ_USER_STRING );
<span style="white-spacere BSTR bstrPassword<span style="white-spacere
= ::SysAllocString( WSZ_PWD_STRING );
<span style="white-spacere try
<span style="white-spacere {
<span style="white-spacere // Open the ADO Connection
<span style="white-spacere hr = OpenConnection( spConnection, bstrConnectionString, bstrUser, bstrPassword );
<span style="white-spacere if(spConnection)
<span style="white-spacere {
<span style="white-spacere if(SUCCEEDED(hr))
<span style="white-spacere {
<span style="white-spacere // Create the ADO Command object
<span style="white-spacere hr = CoCreateInstance(CLSID_CADOCommand, NULL,
<span style="white-spacere CLSCTX_INPROC_SERVER, IID_IADOCommand, (LPVOID *)&spADOCmd);
<span style="white-spacere _bstr_t stored_proc = _T("MySchema.MyStoredProc");
<span style="white-spacere // Set the active connection
<span style="white-spacere hr = spADOCmd->putref_ActiveConnection( spConnection );
<span style="white-spacere hr = spADOCmd->put_CommandText(stored_proc);
<span style="white-spacere hr = spADOCmd->put_CommandType(adCmdStoredProc);
<span style="white-spacere // Create the parameters for my stored procedure
<span style="white-spacere _variant_t vFamilyID<span style="white-spacere
= 1L;
<span style="white-spacere _variant_t vUniqueID<span style="white-spacere
= 2L;
<span style="white-spacere _variant_t vMemberID<span style="white-spacere
= 2L;
<span style="white-spacere
<span style="white-spacere _variant_t vMemberIID(L"{F4DDF1B8-BB56-4293-873F-5D1B6357C30C}");
<span style="white-spacere CComPtr<ADOParameter> spParam1 = NULL;
<span style="white-spacere CComPtr<ADOParameter> spParam2 = NULL;
<span style="white-spacere CComPtr<ADOParameter> spParam3 = NULL;
<span style="white-spacere CComPtr<ADOParameter> spParam4 = NULL;
<span style="white-spacere CComPtr<ADOParameters> spParams = NULL;
<span style="white-spacere
<span style="white-spacere hr = spADOCmd->get_Parameters( &spParams );
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("FamilyID")), adInteger,
<span style="white-spacere adParamInput, 4, vFamilyID, &spParam1);
<span style="white-spacere hr = spParams->Append(spParam1);
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("UniqueID")), adInteger,
<span style="white-spacere adParamInput, 4, vUniqueID, &spParam2);
<span style="white-spacere hr = spParams->Append(spParam2);
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("MemberIID")), adGUID,
<span style="white-spacere adParamInput, 255, vMemberIID, &spParam3);
<span style="white-spacere hr = spParams->Append(spParam3);
<span style="white-spacere hr = spADOCmd->CreateParameter( _bstr_t(_T("MemberID")), adInteger,
<span style="white-spacere adParamInput, 4, vMemberID, &spParam4);
<span style="white-spacere hr = spParams->Append(spParam4);
<span style="white-spacere // Create the ADO record set object
<span style="white-spacere CComPtr<ADORecordset> spRS;
<span style="white-spacere hr = CoCreateInstance(CLSID_CADORecordset, NULL, CLSCTX_INPROC_SERVER,
<span style="white-spacere IID_IADORecordset, (LPVOID *)&spRS);
<span style="white-spacere _variant_t vtSource = spADOCmd;
<span style="white-spacere _variant_t vNull;<span style="white-spacere
<span style="white-spacere V_VT(&vNull) = VT_ERROR;
<span style="white-spacere V_ERROR(&vNull) = DISP_E_PARAMNOTFOUND;
<span style="white-spacere hr = spRS->put_CursorLocation( adUseClient );
<span style="white-spacere // Open the recordset with the ADO command object (passed in as vtSource)
<span style="white-spacere hr = spRS->Open( vtSource, vNull, adOpenKeyset, adLockOptimistic,
<span style="white-spacere adCmdStoredProc );
<span style="white-spacere if(SUCCEEDED(hr))
<span style="white-spacere {
<span style="white-spacere VARIANT_BOOL<span style="white-spacere
vbEOF;
<span style="white-spacere hr = spRS->get_EOF(&vbEOF);
<span style="white-spacere }
<span style="white-spacere // Should not *have* to do this, as the smart pointers should release
<span style="white-spacere // the object when it goes out of scope.
<span style="white-spacere // Setting to NULL Should release the last reference to the ADO paramx object.
<span style="white-spacere spParam1 = NULL;
<span style="white-spacere spParam2 = NULL;
<span style="white-spacere spParam3 = NULL;
<span style="white-spacere spParam4 = NULL;
<span style="white-spacere spParams = NULL;
<span style="white-spacere // Setting to NULL Should release the last reference to the ADO params object.
<span style="white-spacere spParams = NULL;
<span style="white-spacere // Setting to NULL Should release the last reference to the ADO command object.
<span style="white-spacere spADOCmd = NULL;
<span style="white-spacere spRS->Close();
<span style="white-spacere spRS = NULL;
<span style="white-spacere spConnection->Close();<span style="white-spacere
// Close the connection
<span style="white-spacere }
<span style="white-spacere spConnection = NULL;<span style="white-spacere
// Release the connection COM object
<span style="white-spacere }
<span style="white-spacere }
<span style="white-spacere catch(...)
<span style="white-spacere {
<span style="white-spacere }
<span style="white-spacere if( bstrConnectionString )
<span style="white-spacere ::SysFreeString( bstrConnectionString );
<span style="white-spacere bstrConnectionString = NULL;
<span style="white-spacere if( bstrUser )
<span style="white-spacere ::SysFreeString( bstrUser );
<span style="white-spacere bstrUser = NULL;
<span style="white-spacere if( bstrPassword )
<span style="white-spacere ::SysFreeString( bstrPassword );
<span style="white-spacere bstrPassword = NULL;
<span style="white-spacere return hr;
}
HRESULT CADO_LeakDlg::OpenConnection( CComPtr<ADO::ADOConnection> &spConnection,
BSTR bstrConnectionString, BSTR bstrUser, BSTR bstrPassword )
{
<span style="white-spacere HRESULT hr = S_OK;
<span style="white-spacere hr = CoCreateInstance(CLSID_CADOConnection, NULL,
<span style="white-spacere CLSCTX_INPROC_SERVER, IID_IADOConnection, (void **)&spConnection);
<span style="white-spacere if(FAILED(hr))
<span style="white-spacere return hr;<span style="white-spacere
// Failed to create the connection object
<span style="white-spacere hr = spConnection->Open( bstrConnectionString, bstrUser, bstrPassword, adOpenUnspecified );
<span style="white-spacere return hr;
}
<br/>
View the full article