我有一段代码使用静态方法 Process.GetProcessesByName(String, String) 获取远程计算机上的进程列表,这可以在很多计算机(几千台)上运行,我注意到这是导致严重内存泄漏的原因。
我运行了 ANTS 内存分析器,它告诉我我的大部分内存都由字符串占用,字符串包含诸如“% Idle Time”、“处理器信息”和“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;
}
}
最佳答案
您可以调用PerformanceCounter.CloseSharedResources .
在内部,这会调用 PerformanceCounterLib.CloseAllLibraries
,这听起来像。
我建议您确保在没有调用 GetProcessesByName
时调用它,因为看起来 PerformanceCounterLib
中可能存在一些竞争条件> 你不想激怒。
即有一个名为 libraryTable
的共享变量被检查一次,然后假定它在一种方法中继续有效,但可能随时被 CloseAllLibraries
清除 - 所以它绝对不是线程安全。
关于c# - Process.GetProcessesByName(String, String) 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13084585/