【问题标题】:OutOfMemoryException for a vb.net applicationvb.net 应用程序的 OutOfMemoryException
【发布时间】:2013-07-17 13:24:37
【问题描述】:

在我的一个 VB.Net 应用程序中,我在运行该应用程序时遇到错误。这个错误并不总是出现。所以我也无法重现该错误。也没有确切的顺序来重现错误。

堆栈:System.OutOfMemoryException:内存不足。 在 System.Drawing.Graphics.FromHdcInternal(IntPtr hdc) 在 System.Windows.Forms.ToolStrip.OnPaint(PaintEventArgs e) 在 System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e,Int16 层,布尔 disposeEventArgs) 在 System.Windows.Forms.Control.WmPaint(消息和 m) 在 System.Windows.Forms.Control.WndProc(消息和 m) 在 System.Windows.Forms.ScrollableControl.WndProc(消息和 m) 在 System.Windows.Forms.ToolStrip.WndProc(消息和 m) 在 System.Windows.Forms.StatusStrip.WndProc(消息和 m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

错误描述:

MyApplication_UnhandledException

在这个错误之后,我收到一条消息说,

内存不足,无法创建位图。关闭一个或多个应用程序以增加可用性。

当我检查应用程序的内存使用情况时,它并没有那么高。此错误不会重复出现。那么我该如何解决这个错误。如何解决? 我使用 .Net 内存分析器和 redgate 内存分析器检查了我的应用程序的运行情况。

以下是非托管内存使用量的屏幕截图。我不知道这些值是否很高。

更新:

我又得到了错误。检查了 gdi 对象,它是 9998。所以错误是由于高 gdi 对象造成的。现在问题是如何解决。然后我使用GDIView 并检查。通过那个工具我得到了笔-2954 画笔 5918 字体 90 位图 13 等 GDI 总计 9998 那么这些钢笔和画笔是什么?在我的代码中,我没有使用画笔或钢笔。(我在代码中搜索了“钢笔”和“画笔”但没有得到任何东西。)所以请帮助我

【问题讨论】:

  • 你为 Tooltip 分配了什么?
  • 您能出示您的代码吗?最好是一些与位图一起使用的部分?
  • 唯一明显的是您大量使用 ActiveX 控件。这可以防止垃圾收集器经常运行以使您摆脱麻烦。当您不在 System.Drawing 对象上使用 Dispose() 时遇到的那种麻烦。当你用完太多手柄时,它会像这样爆炸。

标签: vb.net memory-management error-handling out-of-memory


【解决方案1】:

在您的任务管理器中,转到查看菜单以选择要在进程标签中显示的列。选择要显示 GDI 对象 列。我相当肯定您会看到您的进程的 GDI 对象总数达到 10000,这是所有进程的最大值。

这与使用了多少物理内存无关。从这个意义上说,错误消息非常糟糕且具有误导性。问题是您已经用完了 GDI 句柄。 Windows 下的每个进程都被限制为它们可以创建的最大 GDI 句柄数。当前限制为每个进程 10000 个句柄。

我假设您的问题是 GDI 句柄的原因是因为在绘制控件的过程中尝试创建新位图时会引发异常。位图是一个 GDI 对象。创建位图会占用该位图的 GDI 句柄。因此,这很可能是原因。

由于标准ToolStrip 控件中发生错误,因此ToolStrip 本身不太可能是错误。很有可能您在程序的其他地方用尽了所有 GDI 句柄,然后,当控件尝试绘制自身时,由于没有剩余句柄而失败。

每当您创建 GDI 对象(如钢笔和位图)时,您都需要确保处置这些对象。所有获取 GDI 句柄的 GDI 类都实现了IDisposable 接口。当对象被释放时,它们会在此时自动删除它们的句柄。但是,如果您从不处置对象,则句柄永远不会被删除,您的 GDI 对象数量将继续增长。

要处理任何IDisposable 对象,您可以在处理完对象后简单地调用Dispose 方法,例如:

Dim b As New Bitmap("test.bmp")
'...
b.Dispose()

但是,如果可以,最好使用 Using 块声明 IDisposable 对象的变量,如下所示:

Using b As New Bitmap("test.bmp")
    '...
End Using

使用Using 块,Dispose 方法将自动为您调用,因此您无需自己显式调用它。 Using 块比自己调用 Dispose 更好的原因是,如果在 Using 块内抛出异常,Dispose 方法仍然会被自动调用。如果您自己显式调用它,而没有 Using 块,则更容易错过您需要调用它的每个地方。

要查找代码中的问题区域,请在调试器中运行程序并单步调试代码。让Task Manager保持打开状态,显示GDI Objects列,同时单步执行代码。观察 Task Manager 中的 GDI Objects 列,您会看到计数随着新 GDI 对象的创建而增加。使用这种方法应该很容易看出问题出在哪里。

【讨论】:

  • 在我的应用程序中单击网格期间,Msflexgrid 没有处理。每次单击网格都会增加 gdi 对象并得到解决方案。然后我通过在调试器中运行程序解决了问题。现在问题是已解决,现在 gdi 计数保持在 250 到 300。非常感谢。
【解决方案2】:

我并不是说这是答案,但它对我有用 - 最终!我有不同大小的带有 jpg 和其他图片的剪贴画文件夹。我正在组合一个 vb.net 应用程序,使用 datagridview 来显示图片库。对于某些文件夹,它运行良好,而对于其他文件夹则因“内存不足”而失败。我找了很久,然后检查了文件夹中的实际内容。我有一个额外的文件 INDEX.DAT,一旦我编码忽略这个文件 - 问题就消失了!

【讨论】:

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