Argonaut
asked on
Can't find a memory leak
I have a windows service that has a nagging memory leak. I am not the code author so there are things I don't understand yet. If I watch memory usage in task manager I see the available memory slowly decrease as my process usage increases. My process then seems to release the memory but the system available never reclaims it. Eventually all memory is used. I found that the use of CreateThread is not recommended so I tried beginthreadex but that did not help. I'm thinking that maybe a thread is not completeing successfully and then not being released. But since I'm not really a C++ or threading expert I'm not sure what to do. Here is the main cpp file, I can post others if required.
void CAISController::Start()
{
long lCount = 0;
long lVal = 0;
long lReasonCode = 0;
CString csMsgID;
CString csRequest;
CString csReply;
CString csErrorMsg;
CQueueManager objQueueManager;
HANDLE hThreadHandle;
HANDLE hReplyThreadHandle;
DWORD dwThreadID = 0;
DWORD dwSuspendCount = 0;
DWORD dwExitCode = 0;
tagReplyStruct* pReplyStruct = NULL;
tagRequestStruct* pRequestStruct = NULL;
int nIndex = 0;
int nReplyIndex = 0;
int nConnIndex = 0;
int nCount = 0;
CPtrArray colReplyStructHandles;
CPtrArray colStaticConnectPoolHandle s;
void* pContext = NULL;
CStaticConnectionPool* pobjStaticConnectionPool = NULL;
CTiming* pobjTiming = NULL;
MSG msg;
// initializes cae for multi-threaded static sql
sqleSetTypeCtx(SQL_CTX_MUL TI_MANUAL) ;
try
{
// create max request thread semaphore to limit the total request threads
g_hMaxRequestThreadSemapho re = CreateSemaphore(NULL,
g_objApp->GetAppThreadMax( ),
g_objApp->GetAppThreadMax( ),NULL);
// create max database connection semaphore to limit the total connections
g_hMaxConnectionSemaphore = CreateSemaphore(NULL, // no security attributes
g_objApp->GetDBMaxConnecti ons(),
g_objApp->GetDBMaxConnecti ons(),
NULL); // unnamed semaphore
//call the CodeText Build
g_objCodeText.Build();
if (g_objErrorLog->HasError() )
{
// System error logged during build
// Log a page error to notify support and shutdown
g_bShutDown = true;
csErrorMsg = _T("A severe error was encountered during service start.");
csErrorMsg += _T(" The service will now shutdown.");
g_objErrorLog->Add(0, _T("AISController::Start() "),
csErrorMsg, CErrorLog::SYSTEM_EMAIL_PA GE);
}
objQueueManager.ConnectQue ueManager( );
if (g_objErrorLog->HighestSev erity() < CErrorLog::SYSTEM_EMAIL_PA GE)
{
// it's ok to continue if only a "warning" type error occured
colStaticConnectPoolHandle s.SetSize( g_objApp-> GetDBConne ctionPools ());
nCount = colStaticConnectPoolHandle s.GetSize( );
for(nIndex = 0; nIndex < nCount; nIndex++)
{
// establish Database connections
pobjStaticConnectionPool = new CStaticConnectionPool;
pobjStaticConnectionPool-> Build(g_ob jErrorLog) ;
if (g_objErrorLog->HasError() )
{
// System error logged during build
// Log a page error to notify support
// Shutdown the service
g_bShutDown = true;
csErrorMsg = _T("A severe error was encountered during service start.");
csErrorMsg += _T(" The service will now shutdown.");
g_objErrorLog->Add(0, _T("AISController::Start() "),
csErrorMsg, CErrorLog::SYSTEM_EMAIL_PA GE);
}
colStaticConnectPoolHandle s.SetAt(nI ndex, pobjStaticConnectionPool);
}
colReplyStructHandles.SetS ize(g_objA pp->GetRep lyQueueThr eads());
nCount = colReplyStructHandles.GetS ize();
for(nIndex = 0; nIndex < nCount; nIndex++)
{
// create Reply Threads
pReplyStruct = new tagReplyStruct;
// multi-threaded call
hReplyThreadHandle = ::CreateThread(NULL,
0,
&MultiThreadProcessReply,
(LPVOID)pReplyStruct,
THREAD_PRIORITY_NORMAL,
&dwThreadID);
colReplyStructHandles.SetA t(nIndex, pReplyStruct);
}
nReplyIndex = 0;
nConnIndex = 0;
}
while (g_bShutDown != true)
{
if (pRequestStruct == NULL)
pRequestStruct = new tagRequestStruct;
pRequestStruct->csMessage = objQueueManager.GetRequest Message(&p RequestStr uct->cMsgI D[0]);
pRequestStruct->pobjTiming ->Checkpoi nt(CTiming ::AIS_CONT ROLLER);
if (pRequestStruct->csMessage != "" && g_objErrorLog->HighestSeve rity() < CErrorLog::SYSTEM_EMAIL_PA GE)
{
//thread should go to sleep if all request threads are in use
WaitForSingleObject(g_hMax RequestThr eadSemapho re, INFINITE); // no timeout period
if (nReplyIndex > (colReplyStructHandles.Get Size() - 1))
nReplyIndex = 0;
pRequestStruct->pReplyStru ct = (tagReplyStruct*)colReplyS tructHandl es.GetAt(n ReplyIndex );
if (nConnIndex > (colStaticConnectPoolHandl es.GetSize () - 1))
nConnIndex = 0;
pRequestStruct->pobjStatic Connection Pool = (CStaticConnectionPool*)co lStaticCon nectPoolHa ndles.GetA t(nConnInd ex);
// spawn the Request Thread
hThreadHandle = ::CreateThread(NULL,
0,
&MultiThreadProcessRequest ,
(LPVOID)pRequestStruct,
THREAD_PRIORITY_NORMAL,
&dwThreadID);
::CloseHandle(hThreadHandl e);
nReplyIndex++;
nConnIndex++;
pRequestStruct = NULL;
}
// check to make sure that there are no messages
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE) != 0)
{
// if it is a quit message then set the global
// variable to true
if (msg.message == WM_QUIT)
g_bShutDown = true;
DispatchMessage(&msg);
}
}
if (pRequestStruct != NULL)
delete pRequestStruct;
objQueueManager.Disconnect QueueManag er();
nCount = colReplyStructHandles.GetS ize();
// wake up each thread so it can kill itself and exit normally
for(nIndex = 0; nIndex < nCount; nIndex++)
{
pReplyStruct = (tagReplyStruct*)colReplyS tructHandl es.GetAt(n Index);
// Now that the thread has to die or rather commit sucide, set the event to signaled
::SetEvent(pReplyStruct->h DataAvaila bleEvent);
}
// now wait a couple of seconds until all threads are complete
::Sleep(5000);
// get rid of Reply structures
for(nIndex = 0; nIndex < nCount; nIndex++)
{
pReplyStruct = (tagReplyStruct*)colReplyS tructHandl es.GetAt(n Index);
if (pReplyStruct !=NULL)
delete pReplyStruct;
}
colReplyStructHandles.Remo veAll();
// delete Static Connections
nCount = colStaticConnectPoolHandle s.GetSize( );
for (nIndex=0; nIndex < nCount; nIndex++)
{
pobjStaticConnectionPool = (CStaticConnectionPool*)co lStaticCon nectPoolHa ndles.GetA t(nIndex);
pobjStaticConnectionPool-> Destroy(g_ objErrorLo g);
delete pobjStaticConnectionPool;
}
colStaticConnectPoolHandle s.RemoveAl l();
g_objCodeText.Destroy();
}
catch(...)
{
TRACE("\nCaught Exception in AISController::Start()\n") ;
g_objErrorLog->Add(GetLast Error(), _T("AISController::Start") ,
_T("Unknown Exception Caught"), CErrorLog::SYSTEM_WARNING) ;
}
}
void CAISController::Start()
{
long lCount = 0;
long lVal = 0;
long lReasonCode = 0;
CString csMsgID;
CString csRequest;
CString csReply;
CString csErrorMsg;
CQueueManager objQueueManager;
HANDLE hThreadHandle;
HANDLE hReplyThreadHandle;
DWORD dwThreadID = 0;
DWORD dwSuspendCount = 0;
DWORD dwExitCode = 0;
tagReplyStruct* pReplyStruct = NULL;
tagRequestStruct* pRequestStruct = NULL;
int nIndex = 0;
int nReplyIndex = 0;
int nConnIndex = 0;
int nCount = 0;
CPtrArray colReplyStructHandles;
CPtrArray colStaticConnectPoolHandle
void* pContext = NULL;
CStaticConnectionPool* pobjStaticConnectionPool = NULL;
CTiming* pobjTiming = NULL;
MSG msg;
// initializes cae for multi-threaded static sql
sqleSetTypeCtx(SQL_CTX_MUL
try
{
// create max request thread semaphore to limit the total request threads
g_hMaxRequestThreadSemapho
g_objApp->GetAppThreadMax(
g_objApp->GetAppThreadMax(
// create max database connection semaphore to limit the total connections
g_hMaxConnectionSemaphore = CreateSemaphore(NULL, // no security attributes
g_objApp->GetDBMaxConnecti
g_objApp->GetDBMaxConnecti
NULL); // unnamed semaphore
//call the CodeText Build
g_objCodeText.Build();
if (g_objErrorLog->HasError()
{
// System error logged during build
// Log a page error to notify support and shutdown
g_bShutDown = true;
csErrorMsg = _T("A severe error was encountered during service start.");
csErrorMsg += _T(" The service will now shutdown.");
g_objErrorLog->Add(0, _T("AISController::Start()
csErrorMsg, CErrorLog::SYSTEM_EMAIL_PA
}
objQueueManager.ConnectQue
if (g_objErrorLog->HighestSev
{
// it's ok to continue if only a "warning" type error occured
colStaticConnectPoolHandle
nCount = colStaticConnectPoolHandle
for(nIndex = 0; nIndex < nCount; nIndex++)
{
// establish Database connections
pobjStaticConnectionPool = new CStaticConnectionPool;
pobjStaticConnectionPool->
if (g_objErrorLog->HasError()
{
// System error logged during build
// Log a page error to notify support
// Shutdown the service
g_bShutDown = true;
csErrorMsg = _T("A severe error was encountered during service start.");
csErrorMsg += _T(" The service will now shutdown.");
g_objErrorLog->Add(0, _T("AISController::Start()
csErrorMsg, CErrorLog::SYSTEM_EMAIL_PA
}
colStaticConnectPoolHandle
}
colReplyStructHandles.SetS
nCount = colReplyStructHandles.GetS
for(nIndex = 0; nIndex < nCount; nIndex++)
{
// create Reply Threads
pReplyStruct = new tagReplyStruct;
// multi-threaded call
hReplyThreadHandle = ::CreateThread(NULL,
0,
&MultiThreadProcessReply,
(LPVOID)pReplyStruct,
THREAD_PRIORITY_NORMAL,
&dwThreadID);
colReplyStructHandles.SetA
}
nReplyIndex = 0;
nConnIndex = 0;
}
while (g_bShutDown != true)
{
if (pRequestStruct == NULL)
pRequestStruct = new tagRequestStruct;
pRequestStruct->csMessage = objQueueManager.GetRequest
pRequestStruct->pobjTiming
if (pRequestStruct->csMessage
{
//thread should go to sleep if all request threads are in use
WaitForSingleObject(g_hMax
if (nReplyIndex > (colReplyStructHandles.Get
nReplyIndex = 0;
pRequestStruct->pReplyStru
if (nConnIndex > (colStaticConnectPoolHandl
nConnIndex = 0;
pRequestStruct->pobjStatic
// spawn the Request Thread
hThreadHandle = ::CreateThread(NULL,
0,
&MultiThreadProcessRequest
(LPVOID)pRequestStruct,
THREAD_PRIORITY_NORMAL,
&dwThreadID);
::CloseHandle(hThreadHandl
nReplyIndex++;
nConnIndex++;
pRequestStruct = NULL;
}
// check to make sure that there are no messages
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE) != 0)
{
// if it is a quit message then set the global
// variable to true
if (msg.message == WM_QUIT)
g_bShutDown = true;
DispatchMessage(&msg);
}
}
if (pRequestStruct != NULL)
delete pRequestStruct;
objQueueManager.Disconnect
nCount = colReplyStructHandles.GetS
// wake up each thread so it can kill itself and exit normally
for(nIndex = 0; nIndex < nCount; nIndex++)
{
pReplyStruct = (tagReplyStruct*)colReplyS
// Now that the thread has to die or rather commit sucide, set the event to signaled
::SetEvent(pReplyStruct->h
}
// now wait a couple of seconds until all threads are complete
::Sleep(5000);
// get rid of Reply structures
for(nIndex = 0; nIndex < nCount; nIndex++)
{
pReplyStruct = (tagReplyStruct*)colReplyS
if (pReplyStruct !=NULL)
delete pReplyStruct;
}
colReplyStructHandles.Remo
// delete Static Connections
nCount = colStaticConnectPoolHandle
for (nIndex=0; nIndex < nCount; nIndex++)
{
pobjStaticConnectionPool = (CStaticConnectionPool*)co
pobjStaticConnectionPool->
delete pobjStaticConnectionPool;
}
colStaticConnectPoolHandle
g_objCodeText.Destroy();
}
catch(...)
{
TRACE("\nCaught Exception in AISController::Start()\n")
g_objErrorLog->Add(GetLast
_T("Unknown Exception Caught"), CErrorLog::SYSTEM_WARNING)
}
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.