troubleshooting Question

Can't find a memory leak

Avatar of Argonaut
Argonaut asked on
System Programming
2 Comments2 Solutions429 ViewsLast Modified:
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);
      }

}
Join the community to see this answer!
Join our exclusive community to see this answer & millions of others.
Unlock 2 Answers and 2 Comments.
Join the Community
Learn from the best

Network and collaborate with thousands of CTOs, CISOs, and IT Pros rooting for you and your success.

Andrew Hancock - VMware vExpert
See if this solution works for you by signing up for a 7 day free trial.
Unlock 2 Answers and 2 Comments.
Try for 7 days

”The time we save is the biggest benefit of E-E to our team. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange.

-Mike Kapnisakis, Warner Bros