Link to home
Start Free TrialLog in
Avatar of cpeters1
cpeters1

asked on

C++ ADO Command Memory Leak

There appears to be a memory leak in my C++ dll caused by ADO.
My code can open a connection and read data from my SQL server without any leaks. But when I try to write data back to the database it creates a memory leak.

I have used Perfmon to confirm this. The Private Bytes counter increases linearly with time with each iteration of the run.

Here is my initial method:

------------------------------
PointCollectionCls* PointStartup::GeneratePoints(bool useDBase, char PeakTrough, PriceDataCls * PriceData)
{
      PointCollectionCls * PointCollection = new PointCollectionCls(int(PriceData->LatestTick/2));
      bool dataFound=true;
      CString sqlText;
      _variant_t recordsAffected(0L);
      HRESULT hr;
      int nearestLatestTick=1;

      if (useDBase)
      {
            //Search DBase for relevant data
            CnnPtr oCn;
            RecPtr oRecSet;
            RecPtr oRecSet2;
            
            _variant_t vNull;
            vNull.vt = VT_ERROR;
            vNull.scode = DISP_E_PARAMNOTFOUND;

            try
            {
                  oCn.CreateInstance( __uuidof( Connection ) );
                  oRecSet.CreateInstance( __uuidof( Recordset ) );

                  //CString connString = "Driver={SQL Server};Server=" + GetSQLServerName() + ";Trusted_Connection=no;Database=
                  CString connString = "Provider=sqloledb;Data Source=" + GetSQLServerName() + ";Initial Catalog=CPSystem;Uid=sa;Pwd=password;";
                  oCn->CommandTimeout = 240;
                  oCn->Open(connString.AllocSysString(),"sa","password",NULL);
                  sqlText = "EXEC [CP_GetPoints] " + ConvToStr(PriceData->LatestTick) + ", '" + ConvToStr(PriceData->symbol) + "', '" + ConvToStr(PeakTrough) + "'";
                  oRecSet->PutRefActiveConnection(oCn.GetInterfacePtr());
                  hr = oRecSet->Open(_variant_t(sqlText.AllocSysString()), vNull, adOpenForwardOnly, adLockReadOnly, adCmdText);
                  
                  
                  if (oRecSet->GetadoEOF())
                  {
                        dataFound=false;
                  }

                  if (dataFound)
                  {
                        LoadDataFromDBase(*PointCollection, oRecSet);
                  }
                  else
                  {
                        ///*
                        //Check whether previous day's points exist and just update
                        dataFound=true;
                        oRecSet2.CreateInstance( __uuidof( Recordset ) );
                        oRecSet2->PutRefActiveConnection(oCn.GetInterfacePtr());
                        sqlText = "EXEC [CP_GetClosestTickPoints] " +  ConvToStr(PriceData->LatestTick) + ", '" + ConvToStr(PriceData->symbol) + "', '" + ConvToStr(PeakTrough) + "'";
                        hr = oRecSet2->Open(_variant_t(sqlText.AllocSysString()), vNull, adOpenForwardOnly, adLockReadOnly, adCmdText);
                        
                        if (oRecSet2->GetadoEOF())
                        {
                              dataFound=false;
                        }
                        if (dataFound)
                        {
                              nearestLatestTick = oRecSet2->Fields->GetItem("LatestTick")->GetValue().intVal;
                              LoadDataFromDBase(*PointCollection, oRecSet2);
                        }
                        
                        //Save data to DBase
                        SaveDataToDBase(*PointCollection, oCn, *PriceData);
                        
                        oRecSet2->Close();
                        //*/
                  }
                  
                  oRecSet->Close();
                  oCn->Close();
            }
            catch ( _com_error &e)
            {
                  AfxMessageBox(e.Description(), NULL,NULL);
                  delete PointCollection;
                  PointCollection = NULL;
            }
      }
      else
      {
            CreateNewPointCollection(PriceData, PointCollection, PeakTrough);
            //PointFinderCls generates points in ascending order (earliest first, latest last)

      }
      return PointCollection;
}
----------------------------------

Note:
1. useDBase is always set to true
2. the PointCollection object gets deleted in the external parent calling method, so this is not the problem.
3. the external calling method makes multplie calls (1000s of iterations) to GeneratePoints().

The problem is in the SaveDataToDBase() method:

-------------------------
void PointStartup::SaveDataToDBase(PointCollectionCls &PointCollection, CnnPtr &oCn, PriceDataCls &PriceData)
{
      int n;
      CString sqlText;
      short peakVal;
      _CommandPtr oCommand;
      oCommand.CreateInstance( __uuidof( Command ));
      oCommand->ActiveConnection = oCn;
      oCommand->CommandType = adCmdText;
      _variant_t vNull;
      vNull.vt = VT_ERROR;
      vNull.scode = DISP_E_PARAMNOTFOUND;
      sqlText = "";

      for (n=0; n < PointCollection.count; n++)
      {
            if (PointCollection[n].peak) peakVal=1;
            else peakVal=0;
            
            sqlText += "EXEC [CP_InsertPoints] '" + CString(PriceData.symbol) + "', ";
            sqlText += ConvToStr(PointCollection[n].time) + ", " + ConvToStr(PointCollection[n].price) + ", ";
            sqlText += ConvToStr(PointCollection[n].timeEarliestBar) + ", " + ConvToStr(PointCollection[n].timeLatestBar) + ", ";
            sqlText += ConvToStr(PriceData.EarliestTick) + ", " + ConvToStr(PriceData.LatestTick) + ", ";
            sqlText += ConvToStr(peakVal) + ", " +  ConvToStr(PointCollection[n].pointHeight) + ", ";
            sqlText += ConvToStr(PointCollection[n].pointTotalVolume) + ", " +  ConvToStr(PointCollection[n].pointBelowVolume) + ", ";
            sqlText += ConvToStr(PointCollection[n].invPointBelowVolumeLeft) + ", " +  ConvToStr(PointCollection[n].invPointBelowVolumeRight) + ", ";  
            sqlText += ConvToStr(PointCollection[n].avgBarLength) + ", ";
            sqlText += ConvToStr(PointCollection[n].barVolatility) + ", " +  ConvToStr(PointCollection[n].interBarVolatility) + ", ";  
            sqlText += ConvToStr(PointCollection[n].pointSig) + ", " +  ConvToStr(PointCollection[n].stillOpen);
            sqlText += '\n';
      }
      oCommand->CommandText = sqlText.AllocSysString();
      oCommand->Execute(&vNull, &vNull, adExecuteNoRecords);
      oCommand->ActiveConnection = NULL;
}
----------------------------------

Now when I comment out the line:
"oCommand->Execute(&vNull, &vNull, adExecuteNoRecords);"
the memory leak disappers completely!

How can I possibly resolve this?
Avatar of prosh0t
prosh0t

it seems like oCommand->CommandText = sqlText.AllocSysString(); would be causing the problem... I have no idea why it would go away when you comment out the execute command.  Maybe hte compiler knows it doesn't need the previous line and so it discards it.. who knows.

Anyways, try deleting the oCommand->CommandText, and the oCommand object itself.  The rule is, ANYTHIGN that is allocated must be deallocated.


delete oCommand->CommandText;
delete oCommand;

Avatar of cpeters1

ASKER

oCommand is a smart pointer so I cannot "delete" oCommand.
oCommand->CommandText is not a pointer either.

See I've also used oCn->Execute(sqlText.AllocSysString(), NULL, adExecuteNoRecords);
instead of oCommand->Execute(...)
and this gives me the same memory leak.
ASKER CERTIFIED SOLUTION
Avatar of mastoo
mastoo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
mastoo you're a genius! The memory leak has completely gone!
I've spent over a week trying to solve this problem. Thanks very much! : )

:-)