【问题标题】:WPF Application crashes randomly with OOM exceptionWPF 应用程序随机崩溃并出现 OOM 异常
【发布时间】:2014-10-21 04:43:42
【问题描述】:

我已经处理这个问题很久了。有时它会抛出无效操作异常,有时会内存不足。随机用户,可以运行几天,一天内崩溃多次。

我从一位用户那里得到了调用堆栈,但不明白是什么原因造成的。这是一个具有丰富 UI 的 WPF 应用程序。许多视图,列表。使用 PRISM 和区域。

它还使用后台线程侦听 TCP、刷新数据并在 UI 线程上发送 PRISM 通知以进行更新。这个堆栈是否提供了我可能需要检查的任何线索?它不是源于我的代码..

在 MS.Utility.ArrayItemList1[[System.Windows.Freezable+FreezableContextPair, WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]..ctor(Int32) at MS.Utility.FrugalObjectList1[[System.Windows.Freezable+FreezableContextPair, WindowsBase,版本=4.0.0.0,文化=中性, PublicKeyToken=31bf3856ad364e35]].set_Capacity(Int32) 在 MS.Utility.FrugalObjectList`1[[System.Windows.Freezable+FreezableContextPair, WindowsBase,版本=4.0.0.0,文化=中性, PublicKeyToken=31bf3856ad364e35]].Insert(Int32, FreezableContextPair) 在 System.Windows.Freezable.AddContextToList(System.Windows.DependencyObject, System.Windows.DependencyProperty)在 System.Windows.Freezable.AddContextInformation(System.Windows.DependencyObject, System.Windows.DependencyProperty)在 System.Windows.Freezable.AddInheritanceContext(System.Windows.DependencyObject, System.Windows.DependencyProperty)在 System.Windows.DependencyObject.ProvideSelfAsInheritanceContext(System.Windows.DependencyObject, System.Windows.DependencyProperty)在 System.Windows.Freezable.OnFreezablePropertyChanged(System.Windows.DependencyObject, System.Windows.DependencyObject、System.Windows.DependencyProperty)
在 System.Windows.Media.RenderData.PropagateChangedHandler(System.EventHandler, 布尔值)在 System.Windows.UIElement.RenderClose(System.Windows.Media.IDrawingContent) 在 System.Windows.Media.VisualDrawingContext.CloseCore(System.Windows.Media.RenderData) 在 System.Windows.Media.RenderDataDrawingContext.DisposeCore() 在 System.Windows.Media.DrawingContext.System.IDisposable.Dispose() 在 System.Windows.Media.RenderDataDrawingContext.Close() 在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 System.Windows.Controls.DataGridCellsPanel.ArrangeChild(System.Windows.UIElement, Int32,排列状态)在 System.Windows.Controls.DataGridCellsPanel.ArrangeOverride(System.Windows.Size) 在 System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect)
在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 MS.Internal.Helper.ArrangeElementWithSingleChild(System.Windows.UIElement, System.Windows.Size)在 System.Windows.Controls.ItemsPresenter.ArrangeOverride(System.Windows.Size) 在 System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect)
在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 System.Windows.Controls.Control.ArrangeOverride(System.Windows.Size)
在 System.Windows.Controls.Primitives.DataGridCellsPresenter.ArrangeOverride(System.Windows.Size) 在 System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect)
在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 System.Windows.Controls.Grid.ArrangeOverride(System.Windows.Size)
在 System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect)
在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 System.Windows.Controls.Border.ArrangeOverride(System.Windows.Size)
在 System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect)
在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 System.Windows.Controls.Control.ArrangeOverride(System.Windows.Size)
在 System.Windows.Controls.DataGridRow.ArrangeOverride(System.Windows.Size) 在 System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect)
在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 System.Windows.Controls.VirtualizingStackPanel.ArrangeOtherItemsInExtendedViewport(布尔值, System.Windows.UIElement、System.Windows.Size、双精度、Int32、 System.Windows.Rect ByRef,System.Windows.Size ByRef, System.Windows.Point ByRef, Int32 ByRef) 在 System.Windows.Controls.VirtualizingStackPanel.ArrangeOverride(System.Windows.Size) 在 System.Windows.FrameworkElement.ArrangeCore(System.Windows.Rect)
在 System.Windows.UIElement.Arrange(System.Windows.Rect) 在 System.Windows.ContextLayoutManager.UpdateLayout() 在 System.Windows.ContextLayoutManager.UpdateLayoutCallback(System.Object) 在 System.Windows.Media.MediaContext+InvokeOnRenderCallback.DoWork()
在 System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
在 System.Windows.Media.MediaContext.RenderMessageHandlerCore(System.Object) 在 System.Windows.Media.MediaContext.RenderMessageHandler(System.Object) 在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32) 在 MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(System.Object, System.Delegate、System.Object、Int32、System.Delegate)在 System.Windows.Threading.DispatcherOperation.InvokeImpl() 在 System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(System.Object) 在 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback,System.Object,布尔值)在 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback,System.Object,布尔值)在 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback,System.Object)在 System.Windows.Threading.DispatcherOperation.Invoke() 在 System.Windows.Threading.Dispatcher.ProcessQueue() 在 System.Windows.Threading.Dispatcher.WndProcHook(IntPtr,Int32,IntPtr, MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef) 在 MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object) 在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32) 在 MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(System.Object, System.Delegate、System.Object、Int32、System.Delegate)在 System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32) 在 MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
在 MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)在 System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame) 在 System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame) 在 System.Windows.Threading.Dispatcher.Run() 在 System.Windows.Application.RunDispatcher(System.Object) 在 System.Windows.Application.RunInternal(System.Windows.Window) 在 System.Windows.Application.Run(System.Windows.Window) 在 ArturExpress.Main.App.Main()

【问题讨论】:

  • 我建议使用一些分析器来查看实际发生的情况。从这个描述真的很难猜到......
  • 堆栈跟踪的实际异常是什么?它是 OutOfMemoryException 还是其他什么?另外,有没有内部异常?
  • 不幸的是我无法追踪它。它是不可复制的,随机发生在用户机器上(可以好几天)。此堆栈跟踪来自事件日志。这是 OutOfMemoryException。

标签: c# wpf multithreading out-of-memory prism


【解决方案1】:

有一个 set_Capacity 通常会导致尝试分配连续的内存块。如果它足够大,它将从未压缩的大对象堆中请求,因此碎片会使得难以找到连续的内存块来满足请求。

内存分析器将是我的下一步,但如果您遇到其他类型的异常,那么记录会更好。

对于桌面应用程序,我使用 log4net 和内存记录器,其中包含最近 500 条消息的详细信息日志。如果发生异常,我会将其定向到文件中,这样我就可以非常详细地了解导致异常发生的原因。

注意调整某些集合的容量通常需要 3 倍于增长数组所需的内存。这是因为当它们超过当前容量时,它们会分配一个两倍于当前大小的新数组,并将现有项目复制到新数组中。因此,在此过渡期间,集合需要 3 倍的内存,即从中复制当前数组和复制到两倍大的数组。我不知道这是否是这里发生的事情。当您拥有容量经常增长的阵列时,您通常会在内存配置文件中看到不断增加的锯齿模式。

【讨论】:

  • 嗯.. 列表并不大,可能有 400 项。通过删除插入更新项目(这是使可观察数组工作的最佳方法),但没有什么超级疯狂的。我确实使用内存分析器在本地进行了测试,并没有发生任何奇怪的事情。一切正常,我什至用异常的高负载(甚至不接近真实)进行了一些压力测试,内存飙升但在 GC 进来后下降了。
  • 像用户一样尝试几个小时,看看它是否会逐渐使用更多的内存。如果有泄漏,您将开始看到在每次 GC 启动后,它不会下降那么远。如果正在引用不再需要的对象,则可以在 C# 中获得“泄漏”。 IE。您从一个列表中删除项目,但它们仍然在内部从 UI 框架中引用。要么进行大量测试,要么添加详细的日志记录来尝试确定问题出现的情况。否则我们会在黑暗中拍摄。
  • 是的,我知道.. 我确实监控了一天的应用程序。没什么奇怪的。并且用户不会整体抱怨。有 70 个用户,偶尔会有一个用户开始抱怨崩溃。就像这样“最近工作正常。这周它可能每天崩溃一次,但昨天我无法工作,因为它一直在崩溃......”我指责线程代码。审查了所有内容,到处都有错误记录。没有结果...
【解决方案2】:

从此堆栈跟踪可以确定内存不足异常发生在 StackPanel 的 UpdateLayout 期间,其中包含 DataGrid 等。

当要求其中一个 DataGrid 行重新排列自身时,其中一个看起来是冻结列的一部分的单元格(似乎包含一个面板)最终要么从 Frozen 变为 Unfrozen(反之亦然) ) 在尝试构造 FreezableContextPair 对象时发生内存不足异常。

如果没有额外的数据点,就不可能说这是巧合还是因果关系。换句话说,如果另外 10 个堆栈跟踪显示完全相同的跟踪,则可能是一组特定的事件与您的一个网格有关,其中一个网格的列从可冻结变为不可冻结,由于某种原因导致内存不足异常。

如果其他堆栈跟踪显示完全不同的结果,则此特定异常可能是巧合,例如某些东西将内存使用量推到了边缘,而这个特定的操作恰好是将它推到了边缘。

您需要更多数据点来确定,并应要求您的用户在发生这种情况时开始发送堆栈跟踪 + 在内存分析器中运行应用程序以查看是否可以看到任何异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多