Process.GetProcessesByName(String,String)内存泄漏

我有一段代码,使用静态方法Process.GetProcessesByName(String,String)获取远程计算机上的进程列表,这可以在很多计算机上运行(几千个),我注意到它的原因是主要的内存泄漏。

我运行了ANTS内存分析器,它告诉我,我的大部分内存都是字符串,字符串包含诸如“%Idle Time”,“Processor Information”和“Cache Faults / sec”之类的存储值。 我已经认识到这些字符串可能是程序中性能计数器的一部分,问题是我在程序中没有任何性能计数器。

深入挖掘发现这些字符串保存在由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 GetProcessesOnAllComputers(List computerNames) { var result = new List(); 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清除 – 所以它绝对不是线程安全的。

警告:这只是一个非常脏的quickfix,但使用reflection来消除它。

访问私有变量: 我可以使用reflection更改C#中的私有只读字段吗?

使用静态类的示例: 使用Reflection在对象初始化之前设置静态变量值?

您可以使用typeof(Process).GetFields(BindingFlags.Static | BindingFlags.NonPublic)来查找字段等。

我相信快速解决方案会受到警告,因为Process的行为显然不正确。

我正在检查ILSpy并分析了方法的方法调用堆栈。 你是对的,有一个静态哈希表。 我建议:你应该在PerformanceCounter类中调用以下方法:

 // System.Diagnostics.PerformanceCounter /// Frees the performance counter library shared state allocated by the counters. /// 2 ///  ///  ///  ///  ///  ///  ///  public static void CloseSharedResources() { PerformanceCounterPermission performanceCounterPermission = new PerformanceCounterPermission(PerformanceCounterPermissionAccess.Browse, ".", "*"); performanceCounterPermission.Demand(); PerformanceCounterLib.CloseAllLibraries(); } 

它调用PerformanceCounterLib.CloseAllLibraries(); 它处理所有使用过的哈希表。