1

I might be using the term Memory Leak poorly but I'm not sure of any other way to describe it. I have wrote a Windows Service that uses the ManagementEventWatcher class to watch for the launch of a specific instance. Once it sees that instance, it launches another in response. I have managed to successfully test this service on multiple computers with success across the board.

The issue I run into is that when the service launches it uses on average 2400k. However, leaving the services running overnight I find in the morning the process sits at 12000k of private working memory in task manager.

This leads me to believe that the something is not disposing of events but I can not discern what.

I believe it might have something to do with the event arrive line: watcher.EventArrived += new EventArrivedEventHandler...

I believe this because it requires use of the add assignment operator. I'd to test this theory but I'm having trouble discerning where I would place the minus assignment operator. Would directly after the first line clear the line to prevent pooling? Or does anyone see any glaring obvious cleanup methods that I'm missing? Attached is the code that is called by the service:

class Monitor
{
    //Pulls process watching and launch path as well as args from xml config file.
    private static string procWatch = ConfigurationManager.AppSettings["watchFor"];
    private static string filePath = ConfigurationManager.AppSettings["filePath"];
    private static string filePath2 = ConfigurationManager.AppSettings["filePath2"];

    public static ManagementEventWatcher watchforProcess()
    {       
        //Creates ManagementEventWatcher Object to return to the service.
        ManagementScope scope = new ManagementScope(@"\\.\root\CIMV2");
        WqlEventQuery query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 1), "TargetInstance isa \"Win32_Process\"");
        ManagementEventWatcher watcher = new ManagementEventWatcher(scope, query);
        watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
        return watcher;
    }
    public static void watcher_EventArrived(object sender, EventArrivedEventArgs e)
    {
        //Event handler that launches a process if it's name matches proc watch
        string instanceName = ((ManagementBaseObject)e.NewEvent["TargetInstance"])["Name"].ToString();
        if (instanceName.ToLower() == procWatch)
        {
            EventLog.WriteEntry("KaceWatcher", "Kace process found.");
            Process.Start(filePath, filePath2);             
        }
        //Should I place a null here to clear up each instanceName.
    }
    public static void finalize()
    {
        //Used for service stop
        procWatch = null;
        filePath = null;
        filePath2 = null;
    }


}
Bryan
  • 11
  • 2
  • 2
    Your code doesn't appear to put any real pressure on the GC heap so it has no reason to perform a collection. Double-check this with the .NET Memory performance counters visible in Perfmon.exe. This *can* get out of hand when you use System.Management, lots of unmanaged objects under the hood. So you'll have to help, count the number of raised events and call GC.Collect() once in a while. – Hans Passant Nov 04 '16 at 18:16
  • I've never used perfMon before. I'll have to look into that. I ran my own test where I place an Eventlog.WriteEntry() in each block so I could monitor the number of times each instance was called. When reviewing the event log everything seems fine as well. methods aside from the event handler were only called once. The event handler obviously was called for every instance of a process. You could watch the memory usage climb with each trigger so I believe the issue lies in the instanceName. I have some ideas for calling GC.Collect() but I worry they might call too much and cause issues. – Bryan Nov 05 '16 at 00:08

1 Answers1

2

We just experienced the same issue after using ManagementEventWatcher, except much more extreme, memory usage skyrocketing into multi-GB-range since we're getting WMI events fired often.

It turns out the solution was, in the EventArrived event you need to manually call Dispose() on e.NewEvent. You are missing the same cleanup.

ultimA
  • 298
  • 1
  • 9