Process.GetProcessesByName(字符串,字符串)内存泄漏(Process.Ge

2019-07-02 16:12发布

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

我跑蚂蚁内存分析器这告诉我,我的大多数内存被采取的字符串,包含类似“%空闲时间”,“处理器信息”和“缓存错误/秒” strage值的字符串。 我承认这些字符串作为可能是性能计数器的一部分,该计划,问题是我没有在程序中的任何性能计数器。

深入研究发现,这些字符串在哈希表被保持由PerformanceCounterLib保持其通过所存储的所述PerformanceCounterLib类的内部静态构件内部散列表ANOTHER保持(这本身是内部)。

更深进了兔子洞挖,我发现,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;
    }
}

Answer 1:

您可以拨打PerformanceCounter.CloseSharedResources 。

在内部,这个调用PerformanceCounterLib.CloseAllLibraries ,该做的事情听起来像。

我建议确保您每次调用这个时候没有来电GetProcessesByName都在进步,因为它看起来像有可能是里面的一些竞争条件PerformanceCounterLib你不想去招惹。

即有被称为共享变量libraryTable被检查一次,然后假定继续有效的一种方法,然而可能被清除CloseAllLibraries在任何时间-所以它决然不是线程安全的。



Answer 2:

警告:这只是一个很肮脏的quickfix,但使用反射来杀时间关闭。

访问私有变量: 我可以使用反射在C#中改变私有只读字段?

例如使用静态类: 使用反射来设置对象的初始化前的静态变量的值?

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

我相信,速战速决是warrented以来的行为Process显然是不正确的。



Answer 3:

我与ILSpy检查和分析你的方法的方法调用堆栈。 你是对的,也有静态的哈希表。 我建议:你应该在调用PerformanceCounter类下面的方法:

// System.Diagnostics.PerformanceCounter
/// <summary>Frees the performance counter library shared state allocated by the counters.</summary>
/// <filterpriority>2</filterpriority>
/// <PermissionSet>
///   <IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1">
///     <Machine name=".">
///       <Category name="*" access="Browse" />
///     </Machine>
///   </IPermission>
/// </PermissionSet>
public static void CloseSharedResources()
{
    PerformanceCounterPermission performanceCounterPermission = new PerformanceCounterPermission(PerformanceCounterPermissionAccess.Browse, ".", "*");
    performanceCounterPermission.Demand();
    PerformanceCounterLib.CloseAllLibraries();
}

调用PerformanceCounterLib.CloseAllLibraries(); 其处置所有使用哈希表。



文章来源: Process.GetProcessesByName(String, String) Memory Leak