Out of Memory!

Jan 22, 2014 at 10:46 PM
Happens on MultiInstance counters.
We have roughly 20 clients connected at once, and have the server app track its own performance in serving each client.

As clients disconnect, we dispose of the CounterHelper for the instance. This doesn't seem to be enough, as after a while, we get an InvalidOperationException: Custom counters file view is out of memory.

Illustrated in the following test app:
        static void Main(string[] args)
        {
            var i = 0;
            PerformanceHelper.Install(typeof(ClientPerformanceCounters));
            while (true)
            {
                Console.WriteLine(++i);
                
                var helper = PerformanceHelper.CreateCounterHelper<ClientPerformanceCounters>(i.ToString());
                helper.RawValue(ClientPerformanceCounters.ScanDuration, i);
                helper.Dispose();
                // runs out of memory after a few hundred instances were created and disposed.
            }
        }

        [PerformanceCounterCategory("Client Counters", PerformanceCounterCategoryType.MultiInstance, "")]
        public enum ClientPerformanceCounters
        {
            [PerformanceCounter("Scan Duration", "", PerformanceCounterType.NumberOfItems32)]
            ScanDuration
        }
What exactly is the right way to dispose of individual instances?

We've tried to do helper.GetInstance(..).RemoveInstance() which works well, but if we add helper.Dispose() right after, we hit the same out of memory error.

Can we get away without calling helper.Dispose() ??
Developer
Dec 3, 2014 at 7:33 AM
Edited Dec 3, 2014 at 7:43 AM
The issue is that the PerformanceCounterContainer does not remove the instance from its System.Diagnostics.PerformanceCounter object - PerformanceCounter.Dispose() does not do it - it just inherits from Component.Dispose() and adds no additional functionality.
So always call RemoveInstance() when disposing an instance of a multi-instance PerformanceCounter, otherwise your Performance counter instances will grow until the reserved Memory (512 KB by Default) is full.

The correct pattern for the PerformanceCounterContainer.Dispose() should be:
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            this._disposed = true;
            this._performanceCounterInstance.RemoveInstance();
            this._performanceCounterInstance.Dispose();
        }
    }
Developer
Dec 3, 2014 at 7:49 AM
I looked at the code again - there is also BaseInstance, which is not disposed at all - so the correct Syntax should be:
private void Dispose(bool disposing)
{
    if (disposing)
    {
        this._disposed = true;
        this._performanceCounterInstance.RemoveInstance();
        this._performanceCounterInstance.Dispose();
        if (this._performanceCounterBaseInstance != null)
        {
            this._performanceCounterBaseInstance.RemoveInstance();
            this._performanceCounterBaseInstance.Dispose();
        }
    }
}
Coordinator
Dec 3, 2014 at 11:34 AM
Hey!

I see there is still people out there using this code. I'm no longer maintaining it since I move to Java, but It's really nice to see that is still useful.

Geovar, do you want to be part of the developer team so you can fix this issues for all of us? I'm adding you as a developer.