#StackBounty: #.net #dispatcher #bitmapencoder Cannot create more Dispatcher. Runs out of resource?

Bounty: 50

In our application, we are using PngBitmapEncoder to encode and save PNG image in a separate threadtask. After few days of running the application we are seeing Dispatcher cannot be created from Encoder and throws error

Not enough storage is available to process the command

And has the below call stack

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)

As .Net is available open source, got curious of what line inside Dispatcher constructor is throwing the error

    [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);
    }

Update

Updated the constructor code from .net open source. The dispatcher.cs is available here https://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/Dispatcher.cs,078d6b27d9837a35

After some investigation we found that issue occurs after some 15000 iterations(each iteration creates a new thread and calls PngBitmapEncoder). Then found that this is linked to Global Atom Table limit (0x4000 or 16384). More details on Global Atom Table here https://docs.microsoft.com/en-us/archive/blogs/ntdebugging/identifying-global-atom-table-leaks

The dispatcher created each time makes an entry in the Global atom table and on thread exit this entry is not cleared. This leads to leak in Global atom table and when it reaches the max limit, it throws "Not enough storage…." error. This seems like a issue with Microsoft’s handling of Dispatcher. Even the PngBitmapEncoder documentation, I do not see any remark with respect to Dispatcher handling and any explicit shutdown of dispatcher.


Get this bounty!!!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.