微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法创建更多分派器资源用完了吗?

如何解决无法创建更多分派器资源用完了吗?

在我们的应用程序中,我们使用PngBitmapEncoder在单独的线程\任务中编码和保存PNG图像。运行该应用程序几天后,我们看到无法从Encoder创建dispatcher并抛出错误

没有足够的存储空间来处理命令

并具有以下调用堆栈

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开源更新了构造函数代码。您可以在https://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs,078d6b27d9837a35

上找到dispatcher.cs

经过一些调查,我们发现问题发生在大约15000次迭代之后(每次迭代都会创建一个新线程并调用PngBitmapEncoder)。然后发现这与全局原子表限制(0x4000或16384)有关。有关全局原子表的更多详细信息,请点击https://docs.microsoft.com/en-us/archive/blogs/ntdebugging/identifying-global-atom-table-leaks

每次创建的调度程序在全局原子表中创建一个条目,并且在线程退出时不会清除该条目。这会导致“全局原子”表中的泄漏,当达到最大限制时,将引发“存储不足....”错误。这似乎是Microsoft处理dispatcher的问题。即使是PngBitmapEncoder文档,我也看不到有关dispatcher处理和任何显式关闭分派器的评论

解决方法

几年前,我也使用System.Windows.Media.Imaging命名空间中的对象进行后台处理时遇到了这个问题。我碰到了一位微软工程师的博客文章,承认这是一个问题,但是没有足够的兴趣来解决它或达到这种效果的东西。我记得希望他们能在框架修订版中对其进行修复。工程师发布了一个对我有用的解决方案。

我应该提到我曾尝试通过使用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();

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。