4

After running my application (.Net 4.5, 64-bit, WPF) a long time (one to two weeks) I encounter the following app crash:

Faulting application name: XY.exe, Version: 2.12.2.2, Time: 0x5bade142
Faulting module name: KERNELBASE.dll, Version: 6.1.7601.24150, Time: 0x5b0cbc65
Exception code: 0xe0434352
Fault offset: 0x000000000001a06d
Faulting process id: 0x8694
Faulting application start time: 0x01d457228a130410
Faulting application path: C:\Testsysteme\YY.exe
Faulting module path: C:\Windows\system32\KERNELBASE.dll
Report Id: dbfc630b-c61f-11e8-bc27-1866da0d15ef

Application: XY.exe
Frameworkversion: v4.0.30319
Description: The process was terminated due to an unhandled exception
Exception information: System.ComponentModel.Win32Exception
at MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D)
at MS.Win32.HwndWrapper..ctor(Int32, Int32, Int32, Int32, Int32, Int32, Int32, System.String, IntPtr, MS.Win32.HwndWrapperHook[])
at System.Windows.Interop.HwndSource.Initialize(System.Windows.Interop.HwndSourceParameters)
at System.Windows.Interop.HwndSource..ctor(System.Windows.Interop.HwndSourceParameters)
at System.Windows.Controls.Primitives.Popup+PopupSecurityHelper.BuildWindow(Int32, Int32, System.Windows.Media.Visual, Boolean, System.Windows.Interop.HwndSourceHook, System.Windows.AutoResizedEventHandler)
at System.Windows.Controls.Primitives.Popup.BuildWindow(System.Windows.Media.Visual)
at System.Windows.Controls.Primitives.Popup.CreateWindow(Boolean)
at System.Windows.Controls.Primitives.Popup.OnIsOpenChanged(System.Windows.DependencyObject, System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex, System.Windows.DependencyProperty, System.Windows.PropertyMetadata, System.Windows.EffectiveValueEntry, System.Windows.EffectiveValueEntry ByRef, Boolean, Boolean, System.Windows.OperationType)
at System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty, System.Object, System.Windows.PropertyMetadata, Boolean, Boolean, System.Windows.OperationType, Boolean)
at System.Windows.Data.BindingOperations.SetBinding(System.Windows.DependencyObject, System.Windows.DependencyProperty, System.Windows.Data.BindingBase)
at System.Windows.Controls.Primitives.Popup.CreateRootPopup(System.Windows.Controls.Primitives.Popup, System.Windows.UIElement)
at System.Windows.Controls.ToolTip.OnIsOpenChanged(System.Windows.DependencyObject, System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs)
at System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex, System.Windows.DependencyProperty, System.Windows.PropertyMetadata, System.Windows.EffectiveValueEntry, System.Windows.EffectiveValueEntry ByRef, Boolean, Boolean, System.Windows.OperationType)
at System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty, System.Object, System.Windows.PropertyMetadata, Boolean, Boolean, System.Windows.OperationType, Boolean)
at System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty, System.Object)
at System.Windows.Controls.PopupControlService.RaiseToolTipOpeningEvent()
at System.Windows.Threading.DispatcherTimer.FireTick(System.Object)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
at MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)
at System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
at System.Windows.Application.RunDispatcher(System.Object)
at System.Windows.Application.RunInternal(System.Windows.Window)
at XY.App.Main()

Logging of the unhandled exception additionally showed:

System.ComponentModel.Win32Exception (0x80004005): Not enough storage is available to process this command

I already found a link with a basic description of the problem connect.microsoft.com on web.archive.org and I downloaded an ran the AtomMonitor from JordiCorbilla/atom-table-monitor (GitHub). Indeed I found an increasing number of RWM Atoms created by my application over time (approx 4000 after some days). This fits to the exception message. All strings look like the following:

C1FE = HwndWrapper[XY.exe;;b68ce81a-d29f-414b-b63a-3b6979e33dd3]  --RWM

From the exception message I see that a 'Popup' is causing a RegisterClassEx from within the OnIsOpenChanged method.

However, opening and closing several popups in my application and monitoring the count of RWM atoms in parallel, I can't see any increase, that's why I can't find the exact source of the problem. Just after some time, when looking at the statistics again I can see that the count increased.

So my questions are:

  1. Can a Popup be responsible for raising the count of RWM atoms? If yes, is this a bug? Why does it create a new Window and registers these atoms?

  2. Do I use the Popup in a wrong way? Do I have to close/dispose/release something?

  3. Is the Popup the problem at all?

  4. What is the 'normal' number of RWM atoms an application creates or should not exceed, because as far as I know they can't be deleted anymore.

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
Creepin
  • 482
  • 4
  • 20
  • This problem likely has nothing to do with C# or WPF. It is based on the COM technology. A bit of a predecessors of .NET, it has some additional issues and limitations. I added the tag to represent that. – Christopher Oct 24 '18 at 12:49
  • Please translate the stack into english. @Christopher - where do you see COM in there? – Simon Mourier Oct 24 '18 at 13:25
  • Just because the exception popped up when calling `RegisterClassEx` does not mean that this method is responsible for the leak. It was the straw that broke the camel's back (German: Es war der Tropfen, der das Fass zum Überlaufen brachte). Make sure to Dispose all disposable objects (either explicitly or with the using statement)! – Olivier Jacot-Descombes Oct 24 '18 at 13:37
  • @SimonMourier `System.ComponentModel.Win32Exception`. Also "Not enough storage is available to process this command" when we already have a Out of Memory Exception for anything like that from Managed. So it definitely does not relate to Managed Code OOM's. – Christopher Oct 24 '18 at 13:47
  • @SimonMourier I updated the post with the translation – Creepin Oct 24 '18 at 14:09
  • @Christopher As far as I know "Not enough storage is available to process this command" refers to a full atom table and not to too less memory. But I am not an expert with these things at all. – Creepin Oct 24 '18 at 14:10
  • @OlivierJacot-Descombes Yes I see. Other problems may cause the error and this is just what I see. But everytime it happens, the popup is in the stack and we are having many popups/tooltips in our application. So I was wondering why the `OnIsOpenChanged` results in calling the `RegisterClassEx` method which in turn creates an entry in the atom table. – Creepin Oct 24 '18 at 14:13
  • @Christopher - System.ComponentModel is 100% .net, nothing to do with COM beyond the name. Also, although you're right the error comes from the native world (RegisterClassEx), it's no COM, just Windows. – Simon Mourier Oct 24 '18 at 14:22
  • It is inevitable plumbing for any app that creates a window. The likely cause is these windows not getting closed again. Ought to be visible as well in a memory profiler. – Hans Passant Oct 24 '18 at 15:25
  • I agree with Hans. .. Have you looked at the actual window handles for this application? This looks like it might be HWND handles leaking to me. Either use the memory profiler or use the task manager and add "Handles" to the Details column. – Señor CMasMas Oct 24 '18 at 15:41
  • @SeñorCMasMas Does closing a window remove the entry from the atom table? I will have a look in the task manager and memory profiler, thanks. – Creepin Oct 24 '18 at 17:50
  • No, not using low level win32 functions it doesn't. Your entries must be cleaned up by hand before the window gets destroyed or your app will leak. I haven't ever used the atom table from .net so I am not sure if there is a managed class for it. If you used pinvoke to call SetPropA/W or GlobalAddAtom, then yes, you must clean it up before the window gets destroyed. – Señor CMasMas Oct 29 '18 at 16:20
  • After some research, I found the following: It was not related to popups or any "real" windows. Besides that, closing a popup releases the entry from the atom table. We create `WriteableBitmap`s on different tasks for image processing. Always when a new thread is used for this task (creating a WPF control), a Dispatcher gets created which in turn creates a `HwndWrapper`. These resources are not released, if the dispatcher is not shutdown manually. Now we use the workaround from the following links. Instead of WriteableBitmap what should we use to make image processing on non-UI threads? – Creepin Oct 30 '18 at 15:42
  • For more details see https://github.com/tgjones/dynamic-image/issues/1 and https://stackoverflow.com/questions/12624867/why-does-longrunning-task-tpl-with-jpegbitmapdecoder-run-out-of-resources/12628379#12628379 and https://web.archive.org/web/20130727034302/https://connect.microsoft.com/VisualStudio/feedback/details/620588/system-componentmodel-win32exception-0x80004005-not-enough-storage-is-available-to-process-this-command – Creepin Oct 30 '18 at 15:43
  • A good explanation can also be found on this page: https://stackoverflow.com/questions/32137811/resource-leak-when-creating-freezable-objects-in-a-background-thread – Creepin Oct 31 '18 at 18:25

1 Answers1

3

After some research, I found the following: It was not related to popups or any "real" windows. Besides that, closing a popup releases the entry from the atom table.

The cause is: We create WriteableBitmaps on different tasks for image processing. Always when a new thread is used for this task (creating a WPF control), a Dispatcher gets created which in turn creates a HwndWrapper.

These resources are not released, if the dispatcher is not shutdown manually. Now we use the workaround from the following links:

GitHub: Win32Exception is thrown when WPF runs out of internal resources

SO: Why does LongRunning task (TPL) with JpegBitmapDecoder run out of resources?

Microsoft Connect: System.ComponentModel.Win32Exception (0x80004005): Not enough storage is available to process this command

SO: Resource leak when creating freezable objects in a background thread

Creepin
  • 482
  • 4
  • 20