我有一段代码使用静态方法Process.GetProcessesByName(String, String)获取远程计算机上的进程列表,它在很多计算机(数千台)上运行,我注意到这是导致重大的内存泄漏。
我运行了 ANTS 内存分析器,它告诉我,我的大部分内存都是由字符串占用的,字符串包含诸如“% Idle Time”、“Processor Information”和“Cache Faults/sec”之类的 strage 值。我已经认识到这些字符串可能是程序中性能计数器的一部分,问题是我在程序中没有任何性能计数器。
深入挖掘发现这些字符串保存在 PerformanceCounterLib 保存的哈希表中,这些哈希表由存储在 PerformanceCounterLib 类的内部静态成员(本身是内部的)中的另一个哈希表保存。
更深入地挖掘兔子洞,我发现 Process.GetProcesesByName 使用 PerformanceCounterLib 来获取在远程计算机上运行的进程列表,并且对于每台远程计算机,在 PerformanceCounterLib 的静态内部变量中创建和引用另一个 PerformanceCounterLib 实例。这些实例中的每一个都包含我发现的字符串哈希表阻塞了我的内存(每个都在 300-700 kb 之间,这意味着它阻塞了我的大对象堆)。
我没有找到删除那些未使用的 PerformanceCounterLib 实例的方法,它们都是内部的,用户无权访问它们。
如何解决我的记忆问题?这真的很糟糕,我的程序在 24 小时内达到了 5GB(我的服务器的限制)。
编辑:添加了一段应该重现问题的代码(未经测试)。为了澄清:
/// 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;
}
}