Ziv*_*Ziv 8 c# memory performance profiling memory-leaks
我有一段代码,使用静态方法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<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;
}
}
Run Code Online (Sandbox Code Playgroud)
fli*_*erg -1
警告:这只是一个非常肮脏的快速修复,但使用反射来杀死它们。
访问私有变量: 我可以使用反射更改 C# 中的私有只读字段吗?
使用静态类的示例: 在对象初始化之前使用反射设置静态变量值?
您可以使用 的变体typeof(Process).GetFields(BindingFlags.Static | BindingFlags.NonPublic)来查找字段等。
我相信需要快速修复,因为 的行为Process显然是不正确的。