I have a piece of code that gets a list of processes on a remote computer using the static method Process.GetProcessesByName(String, String), this runs on a lot of computers (a few thousands) and I've noticed it's a cause of a major memory leak.
I ran ANTS memory profiler which told me that most of my memory is taken by strings, strings containing strage values like "% Idle Time", "Processor Information", and "Cache Faults/sec". I've recognized those strings as probably being a part of Performance Counters in the program, the problem is I don't have any performance counters in the program.
Digging deeper found out those strings are held in hashtables that are held by PerformanceCounterLib which are held by ANOTHER hashtable that is stored inside an internal static member of the PerformanceCounterLib class (which in itself is internal).
Digging even deeper into the rabbit hole, I've found out that Process.GetProcesesByName uses PerformanceCounterLib to get the process list running on a distant computer and that for each remote computer another PerformanceCounterLib instance is created and referenced in the static internal variable of PerformanceCounterLib. Each of those instances hold that hashtable of strings that I found out is clogging my memory (each of them is between 300-700 kb, meaning it's clogging up my Large Object Heap).
I did not find a way to delete those unused PerformanceCounterLib instances, they are all internal and the user has no access to them.
How can I fix my memory problem? This is REALLY bad, my program hits 5GB (my server's limit) within 24 hours.
EDIT: added a piece of code (not tested) that should reproduce the problem. For clarification:
/// computerNames is a list of computers that you have access to
public List<string> GetProcessesOnAllComputers(List<string> computerNames)
{
var result = new List<string>();
foreach(string compName in computernames)
{
Process[] processes = Process.GetProcesses(compName); // Happens with every method that gets processes on a remote computer
string processString = processes.Aggregate(new StringBuilder(), (sb,s) => sb.Append(';').Append(s), sb => sb.ToString());
result.Add(processString);
foreach (var p in processes)
{
p.Close();
p.Dispose();
}
processes = null;
}
}
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…