无法创建更多调度程序。资源用完了吗?
Cannot create more Dispatcher. Runs out of resource?
在我们的应用程序中,我们使用 PngBitmapEncoder 将 PNG 图像编码并保存在单独的 thread\task 中。 运行 几天后,我们看到无法从编码器创建 Dispatcher 并抛出错误
Not enough storage is available to process the command
并具有以下调用堆栈
System.ComponentModel.Win32Exception (0x80004005): Not enough storage is available to process this command
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
at System.Windows.Threading.Dispatcher..ctor()
at System.Windows.Threading.DispatcherObject..ctor()
at System.Windows.Media.Imaging.BitmapEncoder..ctor(Boolean isBuiltIn)
由于 .Net 是开源的,所以很好奇 Dispatcher 构造函数中的哪一行抛出了错误
[SecurityCritical, SecurityTreatAsSafe]
private Dispatcher()
{
_queue = new PriorityQueue<DispatcherOperation>();
_tlsDispatcher = this; // use TLS for ownership only
_dispatcherThread = Thread.CurrentThread;
// Add ourselves to the map of dispatchers to threads.
lock(_globalLock)
{
_dispatchers.Add(new WeakReference(this));
}
_unhandledExceptionEventArgs = new DispatcherUnhandledExceptionEventArgs(this);
_exceptionFilterEventArgs = new DispatcherUnhandledExceptionFilterEventArgs(this);
_defaultDispatcherSynchronizationContext = new DispatcherSynchronizationContext(this);
// Create the message-only window we use to receive messages
// that tell us to process the queue.
MessageOnlyHwndWrapper window = new MessageOnlyHwndWrapper();
_window = new SecurityCriticalData<MessageOnlyHwndWrapper>( window );
_hook = new HwndWrapperHook(WndProcHook);
_window.Value.AddHook(_hook);
// DDVSO:447590
// Verify that the accessibility switches are set prior to any major UI code running.
AccessibilitySwitches.VerifySwitches(this);
}
更新
更新了 .net 开源的构造函数代码。 dispatcher.cs 可在此处获得 https://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs,078d6b27d9837a35
经过一些调查,我们发现问题发生在大约 15000 次迭代后(每次迭代都会创建一个新线程并调用 PngBitmapEncoder)。然后发现这跟Global Atom Table limit (0x4000 or 16384)有关。有关 Global Atom Table 的更多详细信息,请点击此处 https://docs.microsoft.com/en-us/archive/blogs/ntdebugging/identifying-global-atom-table-leaks
每次创建的调度程序都会在全局原子中创建一个条目table,并且在线程退出时不会清除该条目。这会导致全局原子 table 泄漏,当它达到最大限制时,它会抛出“存储空间不足...”错误。这似乎是 Microsoft 处理 Dispatcher 的问题。即使是 PngBitmapEncoder 文档,我也没有看到任何关于 Dispatcher 处理和任何显式关闭 Dispatcher 的评论。
几年前,我在使用 System.Windows.Media.Imaging
命名空间中的对象进行后台处理时也遇到过这个问题。我看到一位 Microsoft 工程师的博客条目承认这是一个问题,但没有足够的兴趣来解决它或类似的东西。我记得希望他们能在框架的修订版中修复它。工程师发布了适合我的解决方案。
我应该提一下,我已经尝试使用 System.Threading.ThreadPool.QueueUserWorkItem()
或 System.Threading.Tasks.Task.Run()
在线程池中使用该解决方案,但发现该解决方案在线程池中不起作用;也许是因为线程被重用了。我能够解决问题的唯一方法是使用 System.Threading.Thread
来完成工作。以下是有关如何解决此问题并强制释放资源的基本思路。
new System.Threading.Thread(new System.Threading.ThreadStart(() =>
{
// Do some imaging work.
// This asks the dispatcher associated with this thread to shut down right away.
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Normal);
System.Windows.Threading.Dispatcher.Run();
})).Start();
在我们的应用程序中,我们使用 PngBitmapEncoder 将 PNG 图像编码并保存在单独的 thread\task 中。 运行 几天后,我们看到无法从编码器创建 Dispatcher 并抛出错误
Not enough storage is available to process the command
并具有以下调用堆栈
System.ComponentModel.Win32Exception (0x80004005): Not enough storage is available to process this command
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
at System.Windows.Threading.Dispatcher..ctor()
at System.Windows.Threading.DispatcherObject..ctor()
at System.Windows.Media.Imaging.BitmapEncoder..ctor(Boolean isBuiltIn)
由于 .Net 是开源的,所以很好奇 Dispatcher 构造函数中的哪一行抛出了错误
[SecurityCritical, SecurityTreatAsSafe]
private Dispatcher()
{
_queue = new PriorityQueue<DispatcherOperation>();
_tlsDispatcher = this; // use TLS for ownership only
_dispatcherThread = Thread.CurrentThread;
// Add ourselves to the map of dispatchers to threads.
lock(_globalLock)
{
_dispatchers.Add(new WeakReference(this));
}
_unhandledExceptionEventArgs = new DispatcherUnhandledExceptionEventArgs(this);
_exceptionFilterEventArgs = new DispatcherUnhandledExceptionFilterEventArgs(this);
_defaultDispatcherSynchronizationContext = new DispatcherSynchronizationContext(this);
// Create the message-only window we use to receive messages
// that tell us to process the queue.
MessageOnlyHwndWrapper window = new MessageOnlyHwndWrapper();
_window = new SecurityCriticalData<MessageOnlyHwndWrapper>( window );
_hook = new HwndWrapperHook(WndProcHook);
_window.Value.AddHook(_hook);
// DDVSO:447590
// Verify that the accessibility switches are set prior to any major UI code running.
AccessibilitySwitches.VerifySwitches(this);
}
更新
更新了 .net 开源的构造函数代码。 dispatcher.cs 可在此处获得 https://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs,078d6b27d9837a35
经过一些调查,我们发现问题发生在大约 15000 次迭代后(每次迭代都会创建一个新线程并调用 PngBitmapEncoder)。然后发现这跟Global Atom Table limit (0x4000 or 16384)有关。有关 Global Atom Table 的更多详细信息,请点击此处 https://docs.microsoft.com/en-us/archive/blogs/ntdebugging/identifying-global-atom-table-leaks
每次创建的调度程序都会在全局原子中创建一个条目table,并且在线程退出时不会清除该条目。这会导致全局原子 table 泄漏,当它达到最大限制时,它会抛出“存储空间不足...”错误。这似乎是 Microsoft 处理 Dispatcher 的问题。即使是 PngBitmapEncoder 文档,我也没有看到任何关于 Dispatcher 处理和任何显式关闭 Dispatcher 的评论。
几年前,我在使用 System.Windows.Media.Imaging
命名空间中的对象进行后台处理时也遇到过这个问题。我看到一位 Microsoft 工程师的博客条目承认这是一个问题,但没有足够的兴趣来解决它或类似的东西。我记得希望他们能在框架的修订版中修复它。工程师发布了适合我的解决方案。
我应该提一下,我已经尝试使用 System.Threading.ThreadPool.QueueUserWorkItem()
或 System.Threading.Tasks.Task.Run()
在线程池中使用该解决方案,但发现该解决方案在线程池中不起作用;也许是因为线程被重用了。我能够解决问题的唯一方法是使用 System.Threading.Thread
来完成工作。以下是有关如何解决此问题并强制释放资源的基本思路。
new System.Threading.Thread(new System.Threading.ThreadStart(() =>
{
// Do some imaging work.
// This asks the dispatcher associated with this thread to shut down right away.
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Normal);
System.Windows.Threading.Dispatcher.Run();
})).Start();