【发布时间】: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