开发者

How to solve memory leak caused by System.Diagnostics.PerformanceCounter

Summary

I have written a process monitor command-line application that takes as parameters:

  • The process name or process ID
  • A CPU Threshold percent.

What the program does, is watches all processes with the passed name or pid, and if their CPU usage gets over the threshold%, it kills them.

I have two classes: ProcessMonitor and ProcessMonitorList

The former, wraps around System.Diagnostics.PerformanceCounter

The latter is an IEnumarable that allows a list-like structure of the former.

The problem

The program itself works fine, however if I watch the Memory Usage on Task Manager, it grows in increments of about 20kB per second. Note: the program polls the CPU counter through PerformanceCounter every second.

This program needs to be running on a heavily used server, and there are a great number of processes it is watching. (20-30).

Investigation So far

I have used PerfMon to monitor the Private Bytes of the process versus the Total number of Bytes in all Heaps and according to the logic presented in the article referenced below, my results indicate that while fluctuating, the value remains bounded within an acceptable range, and hence there is no memory leak:

Article

I have also used FxCop to analyze my code, and it did not come up with anything relevant.

开发者_StackOverflow社区The Plot Thickens

Not being comfortable with just saying, Oh then there's no memory leak, I investigated further, and found (through debugging) that the following lines of code demonstrate where the leak is occurring, with the arrow showing the exact line.

_pc = new PerformanceCounter("Process", "% Processor Time", processName);

The above is where _pc is initiated, and is in the constructor of my ProcessMonitor class.

The below is the method that is causing the memory leak. This method is being called every second from my main.

public float NextValue()
{
        if (HasExited()) return PROCESS_ENDED;
        if (_pc != null)
        {
            _lastSample = _pc.NextValue();   //<-----------------------
            return _lastSample;
        }
        else return -1;
}

This indicates to me that the leak exists inside the NextValue() method, which is inside the System.Diagnostics.PerformanceCounter class.

My Questions:

  1. Is this a known problem, and how do I get around it?
  2. Is my assumption that the task manager's memory usage increasing implies that there is indeed a memory leak correct?
  3. Are there any better ways to monitor multiple instances of a specific process and shut them down if they go over a specific threshold CPU usage, and then send an email?


So I think I figured it out.
Using the Reflector tool, I was able to examine the code inside System.Diagnostics.

It appears that the NextValue method calls

GC.SuppressFinalization();

This means that (I think, and please correct if I am wrong) that I needed to explicitly call Dispose() on all my classes.

So, what I did is implement IDisposable on all of my classes, especially the one that wrapped around PerformanceCounter.

I wrote more explicit cleanup of my IList<PerformanceMonitor>, and the internals, and voilà, the memory behavior changed.

It oscillates, but the memory usage is clearly bounded between an acceptable range over a long period of time.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜