【发布时间】:2018-11-28 10:52:38
【问题描述】:
我们有一个 WinForms 应用程序,它偶尔会抛出 OutOfMemory 异常。我们无法在任何开发机器上产生这个错误,但它偶尔会发生在我们的一些客户身上。我确信这不是由内存泄漏引起的,而是应用程序试图处理太多数据。这是有道理的,因为只有少数最大的客户遇到了这个问题。然而,问题是我不知道发生这种情况时他们在做什么。我们尝试过询问他们,答案类似于“它只是偶尔发生。”。我们有一个异常报告服务,它记录生产中发生的所有未处理的异常,但由于内存不足的工作原理,罪魁祸首不一定在调用堆栈中。对于这些问题,我从未在调用堆栈中看到我们的任何代码。
有没有办法在抛出这些异常时确定应用程序中发生了什么?例如打开了哪些窗口以及在这些窗口的控件中显示了哪些(多少)信息等。
以下是一些示例调用堆栈:
消息:引发了“System.OutOfMemoryException”类型的异常。 System.Threading.WaitHandle.WaitAny(WaitHandle[] waitHandles, Int32 毫秒超时,布尔退出上下文) System.Net.TimerThread.ThreadProc():436 System.Threading.ThreadHelper.ThreadStart_Context(对象状态):20 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext、ContextCallback 回调、对象状态、布尔值 保留SyncCtx):112 System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback 回调、对象状态、布尔值 保留SyncCtx):0 System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback 回调、对象状态):43 System.Threading.ThreadHelper.ThreadStart():8
--
消息:引发了“System.OutOfMemoryException”类型的异常。 System.Reflection.RuntimeAssembly.GetCodeBase(RuntimeAssembly 程序集,布尔复制名称,StringHandleOnStack retString):-1 System.Reflection.RuntimeAssembly.GetCodeBase(布尔复制名称):0 System.Reflection.RuntimeAssembly.GetName(布尔复制名称):0 System.Reflection.Assembly.GetName():0 System.Windows.Forms.ThreadExceptionDialog..ctor(异常 t):1033 System.Windows.Forms.Application+ThreadContext.OnThreadException(异常 t):57 System.Windows.Forms.Control.WndProcException(异常 e):0 System.Windows.Forms.Control+ControlNativeWindow.OnThreadException(异常 e):0 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 味精,IntPtr wparam,IntPtr lparam):58
【问题讨论】:
-
您可以设置procdump 在客户机器上作为调试器运行,并编写崩溃进程的完整内存转储。然后,您可以将此转储加载到开发计算机上的 Visual Studio 中,并可以使用 Visual Studio 调试器检查应用程序的状态。
-
大客户? - 他们使用虚拟机吗?与物理 PC 相比,它们通常没有设置太多内存。询问他们正在使用什么配置,并尝试在您自己的虚拟机中模拟类似的东西,尽管您永远不会完全复制他们的黄金构建虚拟机。只是一个想法
-
根据我的经验,.NET 中的 OutOfMemory 异常甚至与内存无关。它们是失败的 COM 或 GDI 调用。显然,返回的错误代码是 .NET 无法理解的,因此它使用 OutOfMemory 异常。
-
OOM 的一个重要原因是代码分配了 lot 的临时对象,内存碎片严重到内存分配器无法找到足够的空间来分配新对象.例如,列表将项目存储在数组中,每次满时都必须重新分配。例如,将 1M 项逐个添加到列表中将导致 20 次重新分配,使用 2M*type-size 字节。一个 1M 项目 List
逐项构造将消耗 8MB。创建一个足够大的 capacity列表将显着减少重新分配。 -
@PanagiotisKanavos 没错,但如果这是问题的根源,我们的代码不应该出现在调用堆栈中吗?
标签: c# .net winforms out-of-memory