Link to home
Start Free TrialLog in
Avatar of Argonaut
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 colStaticConnectPoolHandles;
      void* pContext = NULL;
      CStaticConnectionPool* pobjStaticConnectionPool = NULL;
      CTiming* pobjTiming = NULL;
      MSG msg;
      
      // initializes cae for multi-threaded static sql
      sqleSetTypeCtx(SQL_CTX_MULTI_MANUAL);

      try
      {
            // create max request thread semaphore to limit the total request threads
            g_hMaxRequestThreadSemaphore = 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->GetDBMaxConnections(),
                                                                              g_objApp->GetDBMaxConnections(),
                                                                              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_PAGE);
            }

            objQueueManager.ConnectQueueManager();
            if (g_objErrorLog->HighestSeverity() < CErrorLog::SYSTEM_EMAIL_PAGE)
            {
                  // it's ok to continue if only a "warning" type error occured
                  colStaticConnectPoolHandles.SetSize(g_objApp->GetDBConnectionPools());
                  nCount = colStaticConnectPoolHandles.GetSize();

                  for(nIndex = 0; nIndex < nCount; nIndex++)
                  {
                        // establish Database connections
                        pobjStaticConnectionPool = new CStaticConnectionPool;
                        pobjStaticConnectionPool->Build(g_objErrorLog);
                        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_PAGE);
                        }
                        colStaticConnectPoolHandles.SetAt(nIndex, pobjStaticConnectionPool);
                  }

                  colReplyStructHandles.SetSize(g_objApp->GetReplyQueueThreads());
                  nCount = colReplyStructHandles.GetSize();

                  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.SetAt(nIndex, pReplyStruct);
                  }

                  nReplyIndex = 0;
                  nConnIndex = 0;
            }

            while (g_bShutDown != true)
            {

                  if (pRequestStruct == NULL)
                        pRequestStruct = new tagRequestStruct;                  
                  
                  pRequestStruct->csMessage = objQueueManager.GetRequestMessage(&pRequestStruct->cMsgID[0]);

                  pRequestStruct->pobjTiming->Checkpoint(CTiming::AIS_CONTROLLER);

                  if (pRequestStruct->csMessage != "" && g_objErrorLog->HighestSeverity() < CErrorLog::SYSTEM_EMAIL_PAGE)
                  {
                        //thread should go to sleep if all request threads are in use
                        WaitForSingleObject(g_hMaxRequestThreadSemaphore, INFINITE);  // no timeout period

                        if (nReplyIndex > (colReplyStructHandles.GetSize() - 1))
                              nReplyIndex = 0;
                        
                        pRequestStruct->pReplyStruct = (tagReplyStruct*)colReplyStructHandles.GetAt(nReplyIndex);

                        if (nConnIndex > (colStaticConnectPoolHandles.GetSize() - 1))
                              nConnIndex = 0;
                        
                        pRequestStruct->pobjStaticConnectionPool = (CStaticConnectionPool*)colStaticConnectPoolHandles.GetAt(nConnIndex);

                        // spawn the Request Thread
                        hThreadHandle = ::CreateThread(NULL,
                                                           0,
                                                                     &MultiThreadProcessRequest,
                                                                     (LPVOID)pRequestStruct,
                                                                     THREAD_PRIORITY_NORMAL,
                                                                     &dwThreadID);

                        ::CloseHandle(hThreadHandle);

                        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.DisconnectQueueManager();

            nCount = colReplyStructHandles.GetSize();


            // wake up each thread so it can kill itself and exit normally
            for(nIndex = 0; nIndex < nCount; nIndex++)
            {
                  pReplyStruct = (tagReplyStruct*)colReplyStructHandles.GetAt(nIndex);
                  // Now that the thread has to die or rather commit sucide, set the event to signaled
                  ::SetEvent(pReplyStruct->hDataAvailableEvent);
            }

            // 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*)colReplyStructHandles.GetAt(nIndex);
                  if (pReplyStruct !=NULL)
                        delete pReplyStruct;
            }

            colReplyStructHandles.RemoveAll();

            // delete Static Connections
            nCount = colStaticConnectPoolHandles.GetSize();
            for (nIndex=0; nIndex < nCount; nIndex++)
            {
                  pobjStaticConnectionPool = (CStaticConnectionPool*)colStaticConnectPoolHandles.GetAt(nIndex);
                  pobjStaticConnectionPool->Destroy(g_objErrorLog);
                  delete pobjStaticConnectionPool;
            }

            colStaticConnectPoolHandles.RemoveAll();

            g_objCodeText.Destroy();

      }
      catch(...)
      {
            TRACE("\nCaught Exception in AISController::Start()\n");      
            g_objErrorLog->Add(GetLastError(), _T("AISController::Start"),
                  _T("Unknown Exception Caught"), CErrorLog::SYSTEM_WARNING);
      }

}
ASKER CERTIFIED SOLUTION
Avatar of wayside
wayside

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
SOLUTION
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