Skip to content

ProcessHelper.CpuTimesStore: ConcurrentDictionary grows unbounded — memory leak on long-running systems #264

@Christophe-Rogiers

Description

@Christophe-Rogiers

Description

ProcessHelper.cs line 43 — CpuTimesStore.PrevCpuTimes is a ConcurrentDictionary<int, CpuSample> that accumulates entries for every monitored process but never removes stale entries when processes exit.

Code

private static class CpuTimesStore
{
    public static readonly ConcurrentDictionary<int, CpuSample> PrevCpuTimes = new ConcurrentDictionary<int, CpuSample>();
}

Impact

On a server running for months with services that restart regularly, this dictionary accumulates thousands of entries for dead PIDs. Each entry holds a CpuSample with timestamps and CPU time values — small individually, but unbounded growth over time.

Suggested Fix

Periodically prune dead PIDs, e.g. in the performance timer tick:

private static void PruneDeadProcesses()
{
    foreach (var pid in PrevCpuTimes.Keys)
    {
        try { Process.GetProcessById(pid); }
        catch (ArgumentException) { PrevCpuTimes.TryRemove(pid, out _); }
    }
}

Call this every N ticks (e.g. every 60 seconds) to keep the dictionary bounded.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions