为什么我的应用程序随着时间的推移变得反应越来越慢?

12

我正在调试一款C#应用程序,这款应用程序经过几天后变得几乎无法响应。该应用程序每秒计算内存/CPU使用情况,并在主用户界面的页脚中显示它。

导致不响应的原因是获取PerformanceCounter("工作集 - 私有")的RawValue所需的时间过长。几天后,获取RawValue几乎需要一秒钟的时间,从而导致主UI线程被冻结。如果我重新启动计算机,则所有东西都会再次快速运行几天,直到它慢慢变得不太响应。如果我重新编译此应用程序而不包含PerformanceCounter代码(它是开源的),则立即正常运行。

为了排除是应用程序的问题,这里有一些示例代码可以做相同的事情:

static void Main(string[] args)
{
    using (var memoryWorkingSetCounter = new PerformanceCounter("Process", "Working Set - Private", Process.GetCurrentProcess().ProcessName, true))
    {
        while (!Console.KeyAvailable)
        {
            var memoryWorkingSetSw = new Stopwatch();
            memoryWorkingSetSw.Start();
            var memoryWorkingSetValue = memoryWorkingSetCounter.RawValue;
            memoryWorkingSetSw.Stop();
            Console.WriteLine(memoryWorkingSetValue.ToString());
            Console.WriteLine(memoryWorkingSetSw.Elapsed.ToString());
            Thread.Sleep(TimeSpan.FromSeconds(1));
        }
    }
    Console.Read();
}

我让这个程序运行了约2.5天,并将时间以毫秒为单位制成了图表:

graph

是什么原因导致Windows性能计数器随着时间推移变得缓慢?可能有其他应用程序没有清理它吗?有没有一种方法可以调试哪些应用程序也在查看此性能计数器? 我正在使用Windows 10。


1
如果将 PerformanceCounter 变量的作用域缩小到仅限于 .RawValue 调用周围,会发生什么?也许该对象会随着时间保留数据。 - Nathan Werry
从技术上讲,这可能是由于其他原因引起的,比如一个不断启动并且不终止的行为异常进程。页面映射表的碎片化在技术上也是可能的。这不是一个便宜的计数器,很难拥有足够的耐心。一朝被蛇咬,十年怕井绳,这是一个相当无用的统计数据,所以直接放弃它。Process.WorkingSet64值得注意,它使用了一种非常不同的方式来获取信息。但是要测量程序所施加的内存压力,您始终应优先考虑Process.PrivateMemorySize64。 - Hans Passant
查看性能计数器的源代码。对于 .Net Core,它在 https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounter.cs;对于 .Net Framework,它在 https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/PerformanceCounter.cs。 - Yair Halberstadt
如果没有足够的内存压力来引起垃圾回收,我会怀疑随着时间的推移内存碎片化。强制进行垃圾回收可能会很有趣...比如每小时进行一次,看看曲线是否变平。 - Clay
1
你长时间持有该对象直到停止应用程序范围不会退出using,也不会销毁该对象;尝试将此块移动到一个方法中,在while循环中调用该方法。 - Abhinaw Kaushik
显示剩余4条评论
1个回答

1
为什么要在循环内声明Stopwatch? 尽可能删除循环内的任何新声明。
这样做会导致内存随时间增加,而且需要依赖垃圾回收器来完成工作。

静态的void Main(string[] args) { // 在循环外声明 var memoryWorkingSetSw = new Stopwatch(); using (var memoryWorkingSetCounter = new PerformanceCounter("Process", "Working Set - Private", Process.GetCurrentProcess().ProcessName, true)) { while (!Console.KeyAvailable) { // 你的代码 } } Console.Read(); } - Ami Vaknin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接