vb.net应用程序的OutOfMemoryException

时间:2013-07-18 14:19:17

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

在我的一个VB.Net应用程序中,我在运行应用程序时遇到错误。此错误并非总是如此。所以我也无法重现错误。没有确切的序列也可以重现错误。

  

Stack:System.OutOfMemoryException:内存不足。   在System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)   在System.Windows.Forms.ToolStrip.OnPaint(PaintEventArgs e)   在System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e,Int16 layer,Boolean 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(Message& m)   在System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& 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 那么笔和画笔是什么?在我的代码中,我没有使用过刷子或笔。(我在代码中搜索了'笔'和'刷'但没有得到任何东西。)所以请帮我这个

2 个答案:

答案 0 :(得分:8)

任务管理器中,转到查看菜单,选择要在进程标签中显示的列。选择要显示 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()

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

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

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

要在代码中找到问题区域,请在调试器中运行程序并逐步执行代码。在您单步调试代码时,打开任务管理器,显示 GDI对象列。观察任务管理器中的 GDI对象列,您将看到在创建新GDI对象时计数增加。使用这种方法,看看问题出在哪里应该相当容易。

答案 1 :(得分:0)

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

相关问题