【问题标题】:Out of memory exception while loading images加载图像时出现内存不足异常
【发布时间】:2011-06-18 17:24:04
【问题描述】:

我正在使用以下代码将图像作为缩略图加载到 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 at 300dpi - 每张图像大约为 3Mb)

【问题讨论】:

  • 您是否尝试通过删除所有多余的代码并仅尝试加载图像来隔离问题?您是否尝试过将加载的图像(如果它到达那么远)分配到“正常”图像显示控件中?
  • 只加载一张图片还是加载多张图片时内存不足?只是一个特定的图像给您带来麻烦,还是当您尝试加载任何图像时它会失败?图片是不是特别大?请,更多细节或我们能做的最好的就是猜测。
  • @Jim。您好,请问您可以查看更新吗?
  • @Chocol8,任何图像组都会发生这种情况,还是有 1 个特定图像导致这种情况?不幸的是,OOM​​ 异常往往是在处理图像时经常抛出的一般错误。 (好吧,不是一般错误,而是低级错误,不会包含在更具体的错误中。)我之前遇到过这个错误,图像损坏。有时它的图像会像更大的图像一样被解压缩到内存中。 stackoverflow.com/questions/1108607/…
  • 一张 3264x2448 的图像是 7,990,272 像素。如果它是 24 位颜色,那就是每像素 3 字节或每张图像大约 23 兆字节。在磁盘上压缩时它们可能只有 3 MB,但在内存中它将使用完整的未压缩大小。如果您的系统内存很少,则无法加载其中的许多内容。

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


【解决方案1】:

我遇到了同样的问题。 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;
}

【讨论】:

    【解决方案2】:

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

    • 要摆脱文件依赖,您必须复制图像。通过真正将它绘制到一个新的位图,你不能只是复制它。
    • 由于您需要缩略图,并且您的源位图相当大,因此请将其与缩小图像相结合。

    【讨论】:

    • ...我已经准备好发布第三个相关问题...“ACDSee”类型的程序如何管理这个?
    • @chocol:我想 ACDsee 之类的东西会创建缩略图,其余部分使用按需加载。
    【解决方案3】:

    几个想法:

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

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

    最后,不要忘记在不再需要图像和流时对其进行处置。

    【讨论】:

      【解决方案4】:

      Image.FromFile 的文档(与您的FromStream 有关)说,如果文件不是有效的图像格式或 GDI+ 不支持像素格式,它将抛出 OutOfMemoryException。您是否正在尝试加载不受支持的图像类型?

      此外,Image.FromStream 的文档说您必须在图像的生命周期内保持流打开,因此即使您的代码加载了图像,您也可能会遇到错误,因为您正在关闭文件而图像仍处于活动状态。见http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-19
        • 1970-01-01
        • 2010-12-04
        • 1970-01-01
        • 2016-09-02
        • 1970-01-01
        • 1970-01-01
        • 2013-08-27
        相关资源
        最近更新 更多