【问题标题】:Out of Memory problem in Visual Studio 2010 Visual Basic .Net 4.0Visual Studio 2010 Visual Basic .Net 4.0 中的内存不足问题
【发布时间】:2011-09-15 17:48:08
【问题描述】:

我有一个图片数据库和幻灯片放映两个 Windows 窗体程序。

幻灯片不断更新显示的图片框而不增加

每个新的图片切换使用的内存。但是,我有第二种形式

有 50 个图片框,用于显示要添加到数据库中的图片的缩略图。由于每个大小 (57,40) 的图片框都使用小尺寸的缩略图 (

大约 30 个大小 (57,40) 的图片框是从 >3MB 的 .jpg 源文件加载的,IDE 内存使用量上升到大约 2.1GB。 (使用

问题表明,图像的平均 .jpg 文件大小 > 3MB 每个高清佳能相机 .jpg 图像被加载到 30 个显示的缩略图图片框中,我开始开始点击周围选择显示的图片,并且使用的内存迅速增加2.3GB 内存使用导致 Out of Memory 崩溃。

这是 VB2010 或 .NET 4.0 中的错误吗?

一旦所有图片都显示为缩略图,鼠标单击面板上包含所有缩略图的 50 个图片框中的任何一个都会更新表单本身上的单个大图片框,以将图片显示在一个大小为(1024 ,768)。单击任何缩略图时,单个大图片框会显示文件中的相关图片,但同时,每次单击事件的系统内存增加约 240KB。最终,当系统内存使用量超过 2.3GB 时,程序会因内存不足错误而崩溃。

如何让程序恢复同一个图片框使用的内存

只更新了一张图片?

部分代码如下:

' Each Thumbnail has a click event
'PB49 is a PictureBox max size (57,40) used as a thumbnail display, all 50 are on a panel
Private Sub PB49_Click(sender As System.Object, e As System.EventArgs) Handles PB49.Click
    'PB(50) is an Integer Array flagging Pictures to add
    If PB(49) = 1 Then PB(49) = 0 Else PB(49) = 1 
    If PB(49) = 1 Then
        CheckBox49.Checked = True       'Tiny Checkbox on thumbnail
        F$ = ListAddFiles.Items(48)     'ListFileBox of FileNames
        PBx1.Image = Image.FromFile(F$) 'Gets filename and path and loads image into PictureBox
        PBx1.Visible = True 'Large PictureBox (1024,768)shows Pic F$ located on Form
    Else
        CheckBox49.Checked = False
        PBx1.Image = Nothing
        PBx1.Visible = False
    End If
End Sub

我在安装XP PRO 32-Bit SP3 4GB RAM 上使用Visual Studio Ultimate SP1 updated .NET 4.0

【问题讨论】:

  • 你在处理需要处理的对象吗?
  • 你不应该在你的问题中使用这么多?
  • 这绝对是你的错误,而不是 VS。

标签: visual-studio visual-studio-2010 out-of-memory


【解决方案1】:

当您隐藏图像时,是否有可能再次加载图像。 IE。你隐藏它,隐藏的那个会留在那里,稍后会再次添加它。因此,您正在积累大量隐藏图像?

.NET 应用程序中的“内存泄漏”通常是由于未清空引用或从所有集合中删除对象的结果。只要一个对象有来自某个地方的引用,无论是表单中控件集合中的某个控件,还是您自己的集合之一,那么它就会保留在内存中。我不确定您显示/隐藏图片的逻辑是什么,但也许您需要删除图片,并确保您从所有相关控件中清除对它的引用。使用控件集合可以嵌套的方式,很容易错过一个地方。与图像相关的控件可能会产生很多额外的开销,因此如果您隐藏了许多未使用的控件但位于内存中,那么这可能是个问题。

你说你有50个图片框,但是你有没有比集合中没有显示的更多的图片。如果您已将它们加载到集合中,那么无论它们是否显示,它们都可能会占用内存。

需要注意的几件事。

1) 32 位 Windows 中的进程最多可使用 2GB 内存。有一些方法可以在机器上将其配置为 3gb,但通常您不应期望有超过 2gb 的可用空间。 Ojn 最重要的是,通常的内存碎片可能会导致您出现 OutOfMemory 异常,即使您似乎有很多可用内存。

2) 每当您处理 .NET 集合时,通常在内部将它们实现为数组。数组是一个连续的内存块。因此,即使您有足够的可用内存,也可能会出现 OutOfMemory 异常,因为没有足够的连续内存块(由于碎片)。 .NET 试图减少碎片化,但有时就像在拥挤的房间里移动一张巨大的桌子一样,它无法创造奇迹。

3) 由于数组不会动态扩展,因此只要空间不足,集合就必须在内部分配一个新数组。通常它每次都会使数组大小加倍。这是大多数集合的“.Capacity”属性。您应该使用一些调试来监视集合的 .Capacity 和 .Length。每次集合达到该大小时,您都会观察到它加倍。 IE。 128、256等

每当它加倍时,它必须分配一个新数组,然后在释放旧数组之前复制旧数组的内容。因此,如果您有一个包含 256 个(或其他 2 的幂,例如 64 个)项目的集合,然后又添加了一个项目,则该集合在内部分配一个新的 512 个项目数组,然后从前一个数组复制到其中。在这个过渡过程中,内存中有一个 512 和 256 数组。因此,虽然您只需要 257 个项目的空间,但添加第 257 个项目需要三倍的空间 (256+512=768)。

您可以使用堆栈跟踪来确定在尝试将图片添加到集合时是否发生异常,因为在调用中添加时间是集合在需要时展开的位置。您还会注意到调用之前的 Length 是 2 的幂。

因此,如果您有 512mb 的图像并且集合需要扩展以添加更多,.NET 必须找到空间来分配 1gb 的图像数组。因此,在必须扩展其容量的集合过渡期间,它将需要 1.5 GB 的内存。由于碎片,.NET 很难找到一个连续的 1gb 内存块,即使 .NET 采取了所有步骤来最小化碎片,它仍然有很多控制权。 (有人可能会指出引用数组要小得多,但很难说你在处理什么。)

解决方案: 如果您确定这是您的问题的原因,那么解决方案是预测您需要多少项,并提前设置数组的容量。因此,如果您有一个图像列表,那么最好先计算这些图像的数量,然后将集合的容量设置为该数量,也许再加上 10% 之类的。这样,如果你有 300 个项目,你可以将容量设置为 350。这样你就可以提前估计容量并留出一点空间,那么它永远不需要扩展,因此不会经历 3 倍的峰值扩展的内存使用情况。

Google .NET 内存分析器。有很多分析器和 win 调试,可以让您查看内存分配和释放以及碎片的详细信息。

【讨论】:

    【解决方案2】:

    @AaronLS 给出了一个终极理论的答案,所以请阅读并记住它。
    您的代码中的内存泄漏在这里:

    PBx1.Image = Nothing
    PBx1.Visible = False
    

    PBx1.Image 是一个Image 类型的对象,因为您使用Image.FromFile 方法。而ImageIDisposable,这意味着它在非托管代码中使用本机资源。

    您必须在此代码中为 PBx1 显式调用 .Dispose() 方法:

    'PBx1.Image = Nothing
    If PBx1.Image IsNot Nothing Then PBx1.Image.Dispose() End If
    PBx1.Visible = False
    

    【讨论】:

      猜你喜欢
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      相关资源
      最近更新 更多