大多数时候,作为 .Net 开发人员,我们可以自由地在我们的高级抽象世界中胡闹,但有时现实会踢你的私处,告诉你找一个真正懂的人。
我刚刚有过这样的经历之一。我认为将角数据列为项目列表就足够了,以便您了解我们在这里拥有的内容:
- Win2008服务器
- 64位环境
- 多个客户端同时使用的 WPF 应用程序
- Application 是一个启动器,它使用 Process.Start() 打开其他应用程序
- 有时我们会遇到下面列出的异常
System.ComponentModel.Win32Exception (0x80004005): Not enough quota is available to process this command at MS.Win32.UnsafeNativeMethods.PostMessage(HandleRef hwnd, WindowMessage msg, IntPtr wparam, IntPtr lparam) at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable`1 channelSet) at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam) at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam) at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
编辑#1 经过一番检查,这里有更多细节:
启动是一个两步过程,启动器使用 Process.WaitForExit() 启动一个中间窗口
从中间窗口,可以以相同的方式启动其他进程 (Process.WaitForExit)。
由于只打开中间窗口且没有用户交互,启动器进程的句柄数量会随着时间的推移而增加。我们在这里看到的最大增加是 400 --> 6000 个句柄。
编辑中添加的事实真的让我想知道框架中的某个地方是否可能存在句柄泄漏。我正在尝试隔离问题并检查是否可以从头开始重现它。与此同时,任何形式的暗示、想法、支持甚至巧克力都被欣然接受!
编辑#2:为了使流程响应PostMessage()
,我们删除了Thread.WaitForExit
. 相反,我们为 Process 的 Exited 事件添加了一个处理程序,并将 Launcher 发送到一个循环中,如下所示:
while (foo == true)
{
System.Threading.Thread.Sleep(1000);
}
Exited-Handler 设置foo
为 false 并且不执行任何其他操作。尽管如此,Handles 的数量仍在增加(半小时内从 400 增加到 800)。
编辑#3 有趣的事情终于来了。
while (foo == true)
{
System.Threading.Thread.Sleep(1000);
GC.Collect();
}
这使它保持了应有的方式,很少有把手,都很漂亮。现在这让我想知道这里出了什么问题......我将再次与负责的开发人员交谈,以检查启动器的其他功能。到目前为止,我听说它使用XmlDocument.Load()读取了一些配置值,这不是IDisposable
- 使得这里很难产生任何泄漏......