PRB: ADO Disconnected Recordset Appears to Leak Memory when Editing in Place (269842)



The information in this article applies to:

  • Microsoft Data Access Components 2.5
  • Microsoft Data Access Components 2.5 SP1
  • Microsoft Data Access Components 2.6
  • Microsoft Data Access Components 2.7

This article was previously published under Q269842

SYMPTOMS

When you attempt to update the same field repeatedly in an ActiveX Data Objects (ADO) disconnected Recordset, you may see memory increase as if there was a memory leak. This behavior only occurs with certain data types. Please see the "More Information" section of this article for a list of affected data types.

CAUSE

The ADO disconnected Recordset uses a memory-mapped file for storage. When you modify a field of certain types that are affected by this behavior, a new buffer is created at the end of the rowset and the new value is added there. Repeatedly modifying an existing record results in memory increasing continuously as the memory-mapped file gets larger and larger. The update algorithm does not recognize that it is just an in-place update.

Although this behavior appears to be a memory leak, it is not truly a leak because the memory gets reclaimed when the Recordset is released.

STATUS

This behavior is by design.

MORE INFORMATION

Steps to Reproduce Behavior

  1. Create an empty console application project in Microsoft Visual C++.
  2. Insert the following sample code that updates one field of the same record repeatedly:
    
    #undef EOF
    #import "C:\Program Files\Common Files\System\Ado\msado15.dll" no_namespace
    
    void main(void)
    {
    	_RecordsetPtr rs;
    	HRESULT hr = CoInitialize(NULL);
    
    	try 
    	{
    		hr = rs.CreateInstance(__uuidof(Recordset));
    		rs->CursorLocation = adUseClient;
    		rs->Fields->Append("BSTRString",adBSTR,10,adFldUpdatable);
    		hr = rs->Open(vtMissing,vtMissing,adOpenStatic,adLockOptimistic,-1);
    		hr = rs->AddNew();
    		rs->Fields->GetItem("BSTRString")->Value = OLESTR("");
    		//make the leak here
    		//update the first record repeatedly
    		_bstr_t bstrTest("Text to update field to.");
    		rs->MoveFirst();
    		for (int i = 0; i < 100000; i++)
    		{
    			rs->Fields->GetItem("BSTRString")->Value = bstrTest;
    			rs->Update();
    		}
    		rs->Close();
    	}
    	catch(_com_error& e) {
    		_bstr_t bstrErrorMessage(e.ErrorMessage());
    		_bstr_t bstrDescription(e.Description());
    	} 
    
    }
    
    					
  3. Compile and run the application.
  4. Watch this process with PerfMon, and you will notice a steady increase in the Private Bytes counter for the process, similar to what happens with a memory leak.

Affected Data Types

The following types of fields all are subject to this behavior:

TypeSize
adBSTRany
adChar>255
adVarChar>255
adLongVarCharany
adWChar >127
adVarWChar>127
adLongVarWCharany


To prevent the memory increase, use the preceding chart to choose a data type that is not affected by this behavior. For example, an adChar of size 255 or smaller. Closing the recordset frees the memory as well.

Modification Type:MajorLast Reviewed:5/12/2003
Keywords:kbCodeSnippet kbfix kbprb KB269842