Detecting memory leaks in a service

This tutorial describes how to detect memory leaks in a service.

This tutorial covers the following:

    1. Modifying a service to use the NT Service API.
    2. How to use the Memory Validator user interface to detect memory leaks in the service.

Related tutorials:

Detecting memory leaks in an application that is a child process of a service.
Detecting memory leaks in an IIS ISAPI DLL.
Detecting memory leaks in ASP.Net with IIS.
Detecting memory leaks in ASP.Net with Web Development Server.
Detecting detect memory leaks for a child process.

Native services and mixed-mode services

This tutorial applies to all native services and to mixed-mode services that start the service that uses the native Win32 services API.

.Net services

If your service is written entirely in .Net or .Net Core, or your service is mixed-mode with the startup code written in .Net or .Net core you can skip the part of this tutorial relating to the NT Service API and go straight to the detecting memory leaks in a service section.

Example Service

Memory Validator ships with an example service in the examples\service folder in the Memory Validator installation directory.

Installing the example service

  1. Open an administrator mode cmd prompt
  2. Type serviceMV_x64.exe -install

Starting the example service

  1. Open an administrator mode cmd prompt
  2. Type serviceMV_x64.exe -start

or

  1. Start the services control panel (type services in the Windows 10 search bar, then choose the Services app).
  2. Find the service in the list of services, right-click to display the context menu, then choose Start.

Stopping the example service

  1. Open an administrator mode cmd prompt
  2. Type serviceMV_x64.exe -stop

or

  1. Start the services control panel (type services in the Windows 10 search bar, then choose the Services app).
  2. Find the service in the list of services, right-click to display the context menu, then choose Stop.

Uninstalling the example service

  1. Open an administrator mode cmd prompt
  2. Type serviceMV_x64.exe -remove

The service has already been modified to use the NT Service API. In this tutorial, we’ll describe the modifications you would make to the service to make it work correctly with Memory Validator.

What is the NT Service API?

The NT Service API is a simple API that allows you to load the Memory Validator profiling DLL and start the process of collecting detecting memory leaks.

The API also includes some debugging functions to help provide debugging information via log files (the only way to get data out of a service without a connection to the Memory Validator user interface).

Modifying your service to use the NT Service API

  1. Identify your service’s ServiceMain function, and just before that function, add a new function definition called serviceCallback(). In the example service, the ServiceMain is called service_main().

    The purpose of serviceCallback() is to regularly tell the service control manager that the service is alive. This prevents the service from being killed for being unresponsive if the instrumentation of your service takes too long (where too long is defined by the service control manager).

    void serviceCallback(void   *userParam)
    {
       // just tell the Service Control Manager that we are still busy
       // in this example userParam is not used
    
       static DWORD dwCheckPoint = 1;
       
       ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
       ssStatus.dwServiceSpecificExitCode = 0;
    
       ssStatus.dwControlsAccepted = 0;
          
       ssStatus.dwCurrentState = dwCurrentState;
       ssStatus.dwWin32ExitCode = dwWin32ExitCode;
       ssStatus.dwWaitHint = dwWaitHint;
       ssStatus.dwCheckPoint = dwCheckPoint++;
          
       // Report the status of the service to the service control manager.
    
       return SetServiceStatus(sshStatusHandle, &ssStatus);
    }
  2. At the start of service_main() set the log file name and delete the log file, erasing any logging from a previous run of the service. This is to prevent debugging information from one session from interfering with another.
    svlMVStub_setLogFileName(SZLOGFILENAME);
    svlMVStub_deleteLogFile();
    
  3. After the call to RegisterServiceCtrlHandler(), load the Memory Validator profiling DLLs with a call to svlMVStub_LoadMemoryValidator(), or if you’re profiling x86 service from the x64 GUI call svlMVStub_LoadMemoryValidator6432(). The return code should be checked to identify success or to be converted into a human-readable string to be written to the log file.
    #ifdef IS6432
    // x86 with x64 GUI
    errCode = svlMVStub_LoadMemoryValidator6432();
    #else    //#ifdef IS6432
    // x86 with x86 GUI
    // x64 with x64 GUI
    errCode = svlMVStub_LoadMemoryValidator();
    #endif   //#ifdef IS6432
    if (errCode != SVL_OK)
    {
       DWORD   lastError;
    
       lastError = GetLastError();
       svlMVStub_writeToLogFileW(_T("Memory Validator load failed. \r\n"));
       svlMVStub_writeToLogFileLastError(lastError);
       svlMVStub_writeToLogFile(errCode);
    
       svlMVStub_dumpPathToLogFile();
    }
    else
    {
       svlMVStub_writeToLogFileW(_T("Memory Validator load success. \r\n"));
    }
    
  4. Next, we inform Memory Validator about the service callback. This must be done after the Memory Validator DLLs are loaded, not before.
    errCode = svlMVStub_SetServiceCallback(serviceCallback,     // the callback
                                           NULL);               // some user data
    if (errCode != SVL_OK)
    {
       svlMVStub_writeToLogFileW(_T("Setting service callback failed. \r\n"));
       svlMVStub_writeToLogFile(errCode);
    }
    
  5. Finally, we start Memory Validator instrumenting your service to detect memory leak data.
    errCode = svlMVStub_StartMemoryValidator();
    if (errCode != SVL_OK)
    {
       DWORD   lastError;
    
       lastError = GetLastError();
       svlMVStub_writeToLogFileW(_T("Starting Memory Validator failed. \r\n"));
       svlMVStub_writeToLogFileLastError(lastError);
       svlMVStub_writeToLogFile(errCode);
    }
    else
    {
       svlMVStub_writeToLogFileW(_T("Finished loading Memory Validator\r\n"));
    }
    

Detecting memory leaks in the service

Now that the NT Service API has been implemented in your service, we can start collecting memory allocation data from the service.

  1. Choose the Launch > Services > Monitor a service… option.

    Memory Validator launch menu monitor a service

  2. The Monitor a service dialog is displayed.

    Memory Validator monitor a service dialog

    Select the service executable you are going to monitor. For this example, the application is examples\service\Release_2010_x64\serviceMV_x64.exe.

    Choose the appropriate native/mixed-mode/.Net option to specify which types of code you want to detect memory leaks for. Mixed-mode is the default, as this collects memory allocation information for all types of code.

  3. When you click OK, Memory Validator will set up everything needed to interact with the NT Service API and then present you with a dialog box.

    Memory Validator start you service dialog

  4. Start your service
  5. Close the dialog box.
  6. Memory Validator will instrument your service and start collecting memory allocation data.

Finishing detecting memory leaks

To finish detecting memory leaks, you need to stop your service.

Memory Validator will monitor memory allocations and deallocations the service shutdown procedure and then present you with the memory leak report.

I’m not getting any memory allocation data. What can I do?

There are a few things to check.

  1. Have you correctly added the NT Service API to the service? 
  2. Check the log file for any errors. You specified the log file in step 2 with the call
    svlMVStub_setLogFileName(SZLOGFILENAME);
  3. Check the diagnostics tab. If the NT Service API is working correctly Memory Validator will have some data. Information on instrumentation failures will be on the diagnostic tab.
  4. Check the debug information dialog. You can access this from the Tools > DLL Debug Information… menu. This dialog will tell you which DLLs have debug information and which do not. Any DLLs that don’t have debug information you’ll need to ensure that debug information is built for these DLLs and is findable.

Conclusion

You have learned how to add the NT Service API to a native service, how to use Memory Validator to monitor a service, and what to look at to diagnose errors if things don’t work first time.

 

 

Fully functional, free for 30 days