Visual Studio 2010 Visual Basic.Net 4.0中存在内存不足问题



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

幻灯片放映在不增加的情况下不断更新显示的图片框

每次新切换图片时使用的内存。然而,我有第二种形式,

具有50个图片框,用于显示要添加到数据库的图片的缩略图。当每个大小(57,40(的图片框都用一个小尺寸的缩略图(<12K(更新时,IDE使用的内存在我的32位XP系统上从加载任何缩略图之前的大约660MB上升到了1GB多一点。

当从大于3MB的.jpg源文件加载大约30个大小(57,40(的图片框时,IDE内存使用量上升到大约2.1GB。(.jpg图像<=15K不容易遇到问题,所有50个缩略图都可以使用<1.3GB内存(。

问题表现为每个高清佳能相机的平均.jpg文件大小>3MB的图像。jpg图像被加载到30个显示的缩略图框中,我开始点击选择显示的图片,使用的内存迅速增加,超过2.3GB的内存使用量,导致内存不足崩溃。

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

一旦所有图片都显示为缩略图,鼠标点击包含所有缩略图的面板上的50个图片框中的任何一个,就会更新表单本身上的单个大图片框,以在具有大小的单个图片框中显示图片(1024768(。当单击任何缩略图时,单个大型图片框会显示文件中与其关联的图片,但同时,每次单击事件的系统内存会增加约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

隐藏图像时,是否有可能再次加载图像。也就是说,你把它藏起来,隐藏的那个就留在那里,然后再添加。因此,你正在积累大量的隐藏图像?

.NET应用程序中的"内存泄漏"通常是由于没有取消引用或从所有集合中删除对象造成的。只要对象有来自某个地方的引用,或者是窗体中控件集合中的某个控件,或者是您自己的某个集合,那么它就会保留在内存中。我不确定你显示/隐藏图片的逻辑是什么,但也许你需要删除图片,并确保从所有相关控件中清除对它的引用。使用控件集合的嵌套方式,很容易漏掉一个位置。与图像相关的控件可能会有很多额外的开销,所以如果你有很多未使用的控件隐藏在内存中,那么这可能是一个问题。

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

有几件事需要注意。

1( 32位Windows中的进程最多有2GB的可用内存。有一些方法可以在机器上将其配置为3gb,但通常情况下,您不应该期望有超过2GB的内存可用。除此之外,通常的内存碎片会导致OutOfMemory异常,即使看起来你有很多空闲内存。

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

3( 由于数组不是动态扩展的,因此每当空间不足时,集合必须在内部分配一个新数组。U通常每次都会使数组大小加倍。这是大多数集合的"Capacity"属性。您应该使用一些调试来监视集合的Capacity和.Length。每次藏品达到这个尺寸,你都会看到它翻了一番。即128、256等

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

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

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

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

Google.NET内存评测器。这里有很多评测器,还可以通过调试来查看内存分配、释放以及碎片的详细信息。

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

PBx1.Image = Nothing
PBx1.Visible = False

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

您必须在以下代码中显式调用PBx1的.Dispose((方法:

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

最新更新