我正在开展一个大型项目,其中提供了一个自定义(相当不错且强大)的框架,我们必须使用它来显示表单和视图。
有一个抽象类StrategyEditor(从框架中的某个类派生),只要打开一个新的StrategyForm就会实例化。
StrategyForm
(自定义窗口框架)包含StrategyEditor
StrategyEditor
包含StrategyTab
StrategyTab
包含StrategyCanvas
。
这是大类的一小部分,以阐明如果在运行时在内存中分配一个StrategyForm对象,将会创建许多对象。我的组件拥有上面提到的所有这些类,除了StrategyForm
,其代码不在我的控制范围内。
现在,在运行时,用户打开许多策略对象(触发创建新的StrategyForm对象。)创建约。 44个策略对象,我们看到应用程序创建的USER OBJECT HANDLES(我将从这里开始使用UOH)达到大约20k +,而在注册表中,句柄的默认数量是10k。 Read more about User Objects here.在不同的计算机上进行的测试清楚地表明,打开的策略对象的数量与弹出的消息不同 - 如果是44,则在一个m / c上,然后在另一个m / c上打开。
当我们看到弹出消息时,表示应用程序响应缓慢。只需更少的对象就会变得更糟,然后创建窗口框架和后续对象失败。
我们首先想到的是内存问题不够。但是后来reading more about new
in C#帮助理解了如果应用程序内存不足会引发异常。这不是内存问题,我觉得(任务管理器也显示了1.5GB +可用内存。)
M / C规格
Core 2 Duo 2GHz +
4GB RAM
页面文件的80GB +可用磁盘空间
虚拟内存设置:4000 - 5000
我的问题
Q1。这看起来像是一个记忆问题,我错了,不是吗?
Q2。这是否意味着自由UOH耗尽(正如我所想),导致窗口手柄的创建失败?
的 Q3。我们如何避免加载StrategyEditor
对象(超出阈值,密切关注当前使用的UOH)? (我们已经知道如何获取正在使用的UOH数量,所以不要去那里。) 请记住,对new StrategyForm()
的调用超出了我的控制范围。组件。
Q4。我有点困惑 - 什么是处理用户对象? MSDN是在讨论我们创建的任何对象,还是仅讨论某些特定对象,如窗口句柄,光标句柄,图标句柄?
Q5。究竟是什么导致用完UOH? (与Q4几乎相同)
对于能给我一些知识渊博的答案的人,我真的很感激。非常感谢! :)
[更新]
根据Stakx的答案,请注意,正在打开的窗口将仅由用户关闭。这是一种MDI应用程序情况,其中打开了太多的子窗口。因此,无论何时我们都无法调用Dispose
。
答案 0 :(得分:2)
听起来你正在尝试同时创建太多的UI控件。即使剩下内存,你的手柄就会用完。请参阅下面的简要但相当技术性的解释。
我理解用户对象是GUI中的任何对象。至少在Windows XP之前,Windows UI API驻留在USER.DLL
(构成Windows的核心DLL之一)中。基本上,UI由“窗口”组成。所有控件(如按钮,文本框,复选框)在内部都是相同的,即“窗口”。要创建它们,您需要调用Win32 API函数CreateWindow
。然后该函数将返回创建的“窗口”(UI元素或“用户对象”)的句柄。
所以我假设用户对象句柄是此函数返回的句柄。 (Winforms基于旧的Win32 API,因此将使用CreateWindow
函数。)
实际上,您无法创建任意数量的UI控件。通过CreateWindow
检索的所有句柄必须在某个时候被释放。在Winforms中,最简单,最安全的方法是使用using
块或致电Dispose
:
using (MyForm form = new MyForm())
{
if (form.ShowDialog() == DialogResult.OK) ...
}
基本上,所有System.Windows.Forms.Control
都可以是Dispose
d,应该处理掉。有时,这是自动完成的,但你不应该依赖它。当您不再需要UI控件时,始终Dispose
。
有关模态和版本的Dispose
的说明无形式:
ShowDialog
)不会自动处理。你必须自己这样做,如上面的代码示例所示。Show
),因为您无法控制用户何时关闭它。无需明确调用Dispose
!每当您创建UI对象时,Winforms会在内部调用CreateWindow
。这就是句柄的分配方式。并且在对DestroyWindow
进行相应调用之前,它们不会被释放。在Winforms中,该调用是通过任何Dispose
的{{1}}方法触发的。 (注意:虽然我很清楚这一点,但我实际上是在猜测。我可能不是100%正确。使用Reflector查看Winforms内部结构会揭示真相。) < / p>
假设您的System.Windows.Forms.Control
创建了大量的UI控件,我认为您无法做很多事情。如果你不能简化那种控制(关于它创建的子控件的数量),那么你似乎陷入了困境。您只是无法创建无限多的UI控件。
然而,您可以跟踪在任何时间打开多少StrategyEditor
(每当实例化时增加一个计数器,并在关闭时减少它 - 您可以使用表单的StrategyEditor
/ FormClosing
事件,或控件的FormClosed
方法。然后,您可以将同时打开的Dispose
的数量限制为固定数字,例如5.如果超出限制,您可以在构造函数中抛出异常,以便不再创建实例。当然我不能说StrategyEditor
是否会处理你的StrategyForm
构造函数中的异常......
StrategyEditor
在任何一种情况下,限制实例化public class StrategyEditor : ...
{
public StrategyEditor()
{
InitializeComponent();
if (numberOfLiveInstances >= maximumAllowedLiveInstances)
throw ...;
// not a nice solution IMHO, but if you've no other choice...
}
}
的数量似乎是对我的临时修复,并不能解决实际问题。