加载图像时内存不足异常

时间:2011-01-31 16:52:05

标签: vb.net image image-processing memory-leaks memory-management

我正在使用以下代码将图像作为缩略图加载到FlowLayoutPanel控件。不幸的是我得到了OutOfMemory异常。

正如您已经猜到的那样,内存泄漏位于

 Pedit.Image = System.Drawing.Image.FromStream(fs)

那么我怎样才能优化以下代码?

 Private Sub LoadImagesCommon(ByVal FlowPanel As FlowLayoutPanel, ByVal fi As FileInfo)
        Pedit = New DevExpress.XtraEditors.PictureEdit
        Pedit.Width = txtIconsWidth.EditValue
        Pedit.Height = Pedit.Width / (4 / 3)
        Dim fs As System.IO.FileStream
        fs = New System.IO.FileStream(fi.FullName, IO.FileMode.Open, IO.FileAccess.Read)
        Pedit.Image = System.Drawing.Image.FromStream(fs)
        fs.Close()
        fs.Dispose()
        Pedit.Properties.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Zoom

        If FlowPanel Is flowR Then
            AddHandler Pedit.MouseClick, AddressOf Pedit_MouseClick
            AddHandler Pedit.MouseEnter, AddressOf Pedit_MouseEnter
            AddHandler Pedit.MouseLeave, AddressOf Pedit_MouseLeave
        End If

        FlowPanel.Controls.Add(Pedit)
    End Sub

更新:加载大量图片时出现此问题(3264x2448px为300dpi - 每张图片大约为3Mb)

4 个答案:

答案 0 :(得分:5)

Image.FromFile的文档(与您的FromStream相关)表示如果文件不是有效的图片格式或者GDI +不支持像素,它会抛出OutOfMemoryException格式。您是否可能尝试加载不受支持的图像类型?

此外,Image.FromStream的文档说您必须在图像的生命周期内保持流打开,因此即使您的代码加载了图像,您可能会因为关闭文件而收到错误而图像仍然有效。请参阅http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx

答案 1 :(得分:3)

几点想法:

首先,正如Jim所说,当使用Image.FromStream时,流应该在MSDN页面上标注的图像生命周期内保持打开状态。因此,我建议将文件的内容复制到MemoryStream,并使用后者创建Image实例。所以你可以尽快释放文件句柄。

其次,您正在使用的图像相当大(未压缩,因为它们将存在于内存中,宽度x高度x BytesPerPixel)。假设您使用它们的上下文可能允许它们更小,请考虑调整它们的大小,并可能将调整大小的版本缓存到某处以供以后使用。

最后,不要忘记在不再需要时处理图像和流。

答案 2 :(得分:3)

您可以通过以下几个步骤解决此问题:

  • 要摆脱文件依赖性,您必须复制图像。通过真正将其绘制到新的位图,您不能只是复制它。
  • 因为你想要缩略图,而你的源位图相当大,所以将它与缩小图像结合起来。

答案 3 :(得分:0)

我遇到了同样的问题。 Jim Mischel的回答让我发现加载一个无辜的.txt文件是罪魁祸首。如果有人有兴趣,这是我的方法。

这是我的方法:

/// <summary>
/// Loads every image from the folder specified as param.
/// </summary>
/// <param name="pDirectory">Path to the directory from which you want to load images.  
/// NOTE: this method will throws exceptions if the argument causes 
/// <code>Directory.GetFiles(path)</code> to throw an exception.</param>
/// <returns>An ImageList, if no files are found, it'll be empty (not null).</returns>
public static ImageList InitImageListFromDirectory(string pDirectory)
{
    ImageList imageList = new ImageList();

    foreach (string f in System.IO.Directory.GetFiles(pDirectory))
    {
        try
        {
            Image img = Image.FromFile(f);
            imageList.Images.Add(img);
        }
        catch
        {
            // Out of Memory Exceptions are thrown in Image.FromFile if you pass in a non-image file.
        }
    }

    return imageList;
}