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::GeneratePoin ts(bool useDBase, char PeakTrough, PriceDataCls * PriceData)
{
PointCollectionCls * PointCollection = new PointCollectionCls(int(Pri ceData->La testTick/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;Da tabase=
CString connString = "Provider=sqloledb;Data Source=" + GetSQLServerName() + ";Initial Catalog=CPSystem;Uid=sa;Pw d=password ;";
oCn->CommandTimeout = 240;
oCn->Open(connString.Alloc SysString( ),"sa","pa ssword",NU LL);
sqlText = "EXEC [CP_GetPoints] " + ConvToStr(PriceData->Lates tTick) + ", '" + ConvToStr(PriceData->symbo l) + "', '" + ConvToStr(PeakTrough) + "'";
oRecSet->PutRefActiveConne ction(oCn. GetInterfa cePtr());
hr = oRecSet->Open(_variant_t(s qlText.All ocSysStrin g()), vNull, adOpenForwardOnly, adLockReadOnly, adCmdText);
if (oRecSet->GetadoEOF())
{
dataFound=false;
}
if (dataFound)
{
LoadDataFromDBase(*PointCo llection, oRecSet);
}
else
{
///*
//Check whether previous day's points exist and just update
dataFound=true;
oRecSet2.CreateInstance( __uuidof( Recordset ) );
oRecSet2->PutRefActiveConn ection(oCn .GetInterf acePtr());
sqlText = "EXEC [CP_GetClosestTickPoints] " + ConvToStr(PriceData->Lates tTick) + ", '" + ConvToStr(PriceData->symbo l) + "', '" + ConvToStr(PeakTrough) + "'";
hr = oRecSet2->Open(_variant_t( sqlText.Al locSysStri ng()), vNull, adOpenForwardOnly, adLockReadOnly, adCmdText);
if (oRecSet2->GetadoEOF())
{
dataFound=false;
}
if (dataFound)
{
nearestLatestTick = oRecSet2->Fields->GetItem( "LatestTic k")->GetVa lue().intV al;
LoadDataFromDBase(*PointCo llection, oRecSet2);
}
//Save data to DBase
SaveDataToDBase(*PointColl ection, oCn, *PriceData);
oRecSet2->Close();
//*/
}
oRecSet->Close();
oCn->Close();
}
catch ( _com_error &e)
{
AfxMessageBox(e.Descriptio n(), NULL,NULL);
delete PointCollection;
PointCollection = NULL;
}
}
else
{
CreateNewPointCollection(P riceData, 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::SaveDataToDB ase(PointC ollectionC ls &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].timeEar liestBar) + ", " + ConvToStr(PointCollection[ n].timeLat estBar) + ", ";
sqlText += ConvToStr(PriceData.Earlie stTick) + ", " + ConvToStr(PriceData.Latest Tick) + ", ";
sqlText += ConvToStr(peakVal) + ", " + ConvToStr(PointCollection[ n].pointHe ight) + ", ";
sqlText += ConvToStr(PointCollection[ n].pointTo talVolume) + ", " + ConvToStr(PointCollection[ n].pointBe lowVolume) + ", ";
sqlText += ConvToStr(PointCollection[ n].invPoin tBelowVolu meLeft) + ", " + ConvToStr(PointCollection[ n].invPoin tBelowVolu meRight) + ", ";
sqlText += ConvToStr(PointCollection[ n].avgBarL ength) + ", ";
sqlText += ConvToStr(PointCollection[ n].barVola tility) + ", " + ConvToStr(PointCollection[ n].interBa rVolatilit y) + ", ";
sqlText += ConvToStr(PointCollection[ n].pointSi g) + ", " + ConvToStr(PointCollection[ n].stillOp en);
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?
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::GeneratePoin
{
PointCollectionCls * PointCollection = new PointCollectionCls(int(Pri
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;Da
CString connString = "Provider=sqloledb;Data Source=" + GetSQLServerName() + ";Initial Catalog=CPSystem;Uid=sa;Pw
oCn->CommandTimeout = 240;
oCn->Open(connString.Alloc
sqlText = "EXEC [CP_GetPoints] " + ConvToStr(PriceData->Lates
oRecSet->PutRefActiveConne
hr = oRecSet->Open(_variant_t(s
if (oRecSet->GetadoEOF())
{
dataFound=false;
}
if (dataFound)
{
LoadDataFromDBase(*PointCo
}
else
{
///*
//Check whether previous day's points exist and just update
dataFound=true;
oRecSet2.CreateInstance( __uuidof( Recordset ) );
oRecSet2->PutRefActiveConn
sqlText = "EXEC [CP_GetClosestTickPoints] " + ConvToStr(PriceData->Lates
hr = oRecSet2->Open(_variant_t(
if (oRecSet2->GetadoEOF())
{
dataFound=false;
}
if (dataFound)
{
nearestLatestTick = oRecSet2->Fields->GetItem(
LoadDataFromDBase(*PointCo
}
//Save data to DBase
SaveDataToDBase(*PointColl
oRecSet2->Close();
//*/
}
oRecSet->Close();
oCn->Close();
}
catch ( _com_error &e)
{
AfxMessageBox(e.Descriptio
delete PointCollection;
PointCollection = NULL;
}
}
else
{
CreateNewPointCollection(P
//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::SaveDataToDB
{
int n;
CString sqlText;
short peakVal;
_CommandPtr oCommand;
oCommand.CreateInstance( __uuidof( Command ));
oCommand->ActiveConnection
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[
sqlText += ConvToStr(PointCollection[
sqlText += ConvToStr(PriceData.Earlie
sqlText += ConvToStr(peakVal) + ", " + ConvToStr(PointCollection[
sqlText += ConvToStr(PointCollection[
sqlText += ConvToStr(PointCollection[
sqlText += ConvToStr(PointCollection[
sqlText += ConvToStr(PointCollection[
sqlText += ConvToStr(PointCollection[
sqlText += '\n';
}
oCommand->CommandText = sqlText.AllocSysString();
oCommand->Execute(&vNull, &vNull, adExecuteNoRecords);
oCommand->ActiveConnection
}
--------------------------
Now when I comment out the line:
"oCommand->Execute(&vNull,
the memory leak disappers completely!
How can I possibly resolve this?
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.Alloc SysString( ), NULL, adExecuteNoRecords);
instead of oCommand->Execute(...)
and this gives me the same memory leak.
oCommand->CommandText is not a pointer either.
See I've also used oCn->Execute(sqlText.Alloc
instead of oCommand->Execute(...)
and this gives me the same memory leak.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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! : )
I've spent over a week trying to solve this problem. Thanks very much! : )
:-)
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;