【问题标题】:Windows Forms app slows down after about 12 hoursWindows 窗体应用程序在大约 12 小时后变慢
【发布时间】:2025-11-20 16:05:01
【问题描述】:

我办公室的一位程序员在 Windows 窗体中编写了一个非常大的应用程序。无论如何,他在大约 12 小时后一直遇到应用程序变慢的问题。我们已经确认,最终运行缓慢的是实际的事件循环,而不是事件触发后的代码。例如,即使在文本框中输入也会非常慢。他有几个套接字通信线程,我们已经确认它们以正常速度运行。我唯一能想到的是他在整个应用程序中有几个 System.Timers.Timer 实例。他们会是问题吗?该程序通常在无人使用大约 5 或 6 小时后变慢。

我知道可能存在一长串可能的问题。我们只需要一些关于从哪里开始寻找的建议。我已经尝试了所有显而易见的方法。

还有一件事要提。他的架构由一个基本表单组成,其中包括一个带有控件的面板,每个页面都有控件以及 3 个计时器,所有其他表单都继承自这个基本表单。这些表格大概有15个左右,所有的表格都是在启动时加载到内存中的。我们这样做是因为客户抱怨第一次在表单之间切换需要几秒钟。每个表单都可能有五十到一百个我们编写的控件实例供他使用,该控件完成他的所有后端工作。这个控件中有一个静态计时器和一个静态线程——因为无论内存中有多少控件实例,只有一个实例,我无法想象这些是问题所在。基本表单的计时器也是静态的。

我不能保证他的代码的效率,但它在我们的办公室运行得非常好,并且在现场运行了 5 到 6 个小时。

有什么想法吗?

编辑:

我刚和现场的那个人谈过,他问了。第一,其中一个静态计时器的事件处理程序不是静态的——静态计时器如何访问实例方法对我来说似乎很奇怪。其次,定时器的 AutoReset 设置为 true。

更新:

好的,我今天终于和那个人一起看一些代码。

他的班级有几个静态成员,即计时器、一些按钮和用户控件。然后在构造函数中,他在每个静态成员上使用 new 运算符,没有静态 bool isInit 标志。

换句话说,每次创建新表单时都会初始化静态成员,但只会引用最后一个初始化的成员。但是,我会想象表单容器持有对旧对象的引用,因此旧对象永远不会被删除。另外,如果在更改静态成员的引用时要删除对象,这对容器来说不是不好的别名吗?无论哪种方式,错误的泄漏或错误的别名都会导致问题。我希望这是唯一的问题。我让他解决所有这些问题,然后我们将再次测试。

为了雪上加霜,他调用了 GC.KeepAlive(静态计时器),它在构造函数中有一个新的引用。所以,他有 21 个计时器在运行。

【问题讨论】:

  • 贴一些代码,这听起来更像是在咆哮
  • @Woot4Moo 寻求建议是一种咆哮吗?我需要一种解决问题的方法,而代码库有数万行。此外,拥有代码的人正在工作现场等待我为他提供建议。我认为您不需要代码就可以为我提供有关从何处开始查找的想法。
  • 我会从 CLR Profiler 开始。如果这不能帮助您缩小范围,请开始将 StopWatches 放入方法中并记录执行时间。
  • 我猜是内存泄漏,检查 IDisposables
  • 它在您的办公室运行良好但在现场变慢的事实是我要调查的第一个线索。

标签: c# .net winforms performance


【解决方案1】:

你在处理吗?您是否在内存中保存对象?您是否持有其他一些非托管资源。

让它继续运行,等它变慢,附加一个调试器,单步调试,看看你的问题区域中哪些行很慢。

编辑:

如果它只是在现场变慢,那么如果产品是针对特定客户的,那么您应该构建一个尽可能与客户匹配的参考环境。这对未来很有用,现在也可以用于识别可能导致问题的系统之间的差异。

我确实遇到过类似的问题,我们在不同机器上的多个服务之间的后台线程上通过套接字执行了一些远程处理。不幸的是,我不记得确切的细节(叹气。)我记得我们一直按设定的时间间隔请求,但是随着时间的推移,服务的响应时间变慢,最终响应时间超过了设定的时间间隔。这对于前 1000 次左右的调用来说很好,.Net 保持了我们所期望的不断增长的回调堆栈。然而,最终这个列表达到了一些内部限制,消息泵冻结了,包括客户端 GUI 上的所有绘画。通过确保在我们得到回应之前我们不会打电话来解决这个问题。这种竞争状况可能是也可能不是您正在经历的,但我认为可能值得一提。

【讨论】:

  • 感谢您的回答!他抓住记忆中的所有对象。我们没有内存泄漏——这是我让他检查的第一件事。调试的困难在于似乎是事件循环运行缓慢。输入实际代表后,它将以正常速度运行。至少有 6 个线程。除了主 ui 线程之外,所有的都运行良好。
  • 十二个小时总是在一天中的同一时间结束吗?可以在不同的位置复制行为吗?机器的配置是否显得相关?
  • 我当然认为它可能是机器,但我已经检查了所有常见的嫌疑人。电源设置、防火墙、磁盘碎片整理程序。还有什么我应该检查的吗?
  • 嗯,这很有趣,因为我们有一些后台线程运行套接字侦听器。但是,我们不做任何请求。客户端机器在启动时向服务注册,然后服务发送 udp 消息,用于在它接收到每个注册客户端的任何事件上发出信号。侦听器只是在进行异步接收。
  • 我会接受这个作为答案,因为。 A.) 问题是初始化的对象,他失去了对其的引用,但从未被删除。 B.) 物品没有被妥善处理。谢谢。
最近更新 更多