【问题标题】:OutOfMemoryException loading big image to Bitmap object with the Compact FrameworkOutOfMemoryException 使用 Compact Framework 将大图像加载到 Bitmap 对象
【发布时间】:2012-06-14 13:27:04
【问题描述】:

我遇到了内存泄漏问题。

我在button_click 中有此代码:

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

    Dim ms As New IO.MemoryStream
    Dim bm As New Bitmap("\Application Data\imgs\IMG22.jpg")
    bm.Save(ms, Drawing.Imaging.ImageFormat.Jpeg)
End Sub

当我在笔记本电脑上运行 .exe(我的意思是在具有完整 .net 框架的 windows7/32bits 下)时,此代码运行良好,但是当我在具有 WindowsMo​​bile 6.1 的设备中运行应用程序时,应用程序会抛出此异常:

SmartDeviceProject22.exe
OutOfMemoryException

Microsoft.AGL.Common.MISC.HandleAr(PAL_ERROR ar)
at
System.Drawing.Image.Save(Stream stream, ImageFormat format)
at
SmartDeviceProject22.Form1.Button3_Click(Object sender, EventArgs e)
at
....

图像大小约为 200kb,宽度和高度约为 1500px。 图片详情:

  • 尺寸:1536x2048
  • 水平分辨率:72dpi
  • 水平分辨率:72dpi
  • 位深:24
  • 分辨率单位:2
  • 颜色表示:sRGB -

我们将不胜感激。

我尝试了@asawyer 的代码,甚至删除了所有代码、参考等,但问题仍然存在,我猜这与图像的宽度/高度或紧凑框架有关。

还有其他建议吗?

问题的解决和解释 好吧,在测试了真正的问题之后,它不是内存泄漏,正如@pdriegen 所说的内存可用问题。

我将我的代码更改为这个(并在移动设备上进行了测试):

 Dim fs As IO.FileStream = IO.File.OpenRead("\Application Data\ryder\IMG23.jpg")
 Dim arrb(fs.Length) As Byte     
 fs.Read(arrb, 0, arrb.Length)
 fs.Close()
 fs.Dispose()

通过上面的代码(显然),我得到了图像的字节()(数组),并使用 dataSet 存储在数据库中。

结论:将位图对象加载到 memoryStream,这是个坏主意。 非常感谢所有花时间阅读我的问题的人,特别是那些发布答案的人。

解决方案(如果需要在图片框中显示图片):

几周后,这可能是最好的(免费)解决方案: 按照此处的说明实现 ImageHelper:ImageHelper

更新了指向 ImageHelper 的链接 https://opennetcf.com/2010/10/13/loading-parts-of-large-images-in-the-compact-framework/

此类/示例使用来自 OpenNetCF (http://www.opennetcf.com/) 的绘图命名空间

它很好用,它解决了我将大位图加载到内存中的内存问题,实际上我们加载了一个缩略图,因此内存中的大小大大减少并避免了 OutOfMemory 异常问题。

关于克里斯·塔克 我刚刚意识到关于 ImageHelper 和 OpenNetCF 的联合创始人的帖子的作者在 stackoverflow 上,这是他的个人资料:https://stackoverflow.com/users/13154/ctacke

更新链接 https://opennetcf.com/2010/10/13/loading-parts-of-large-images-in-the-compact-framework/

【问题讨论】:

    标签: image memory-leaks bitmap compact-framework opennetcf


    【解决方案1】:

    我认为问题不是内存泄漏。相反,问题是可用内存不足。

    即使压缩后的图像大小为 200kb,当您将其作为位图加载时,它也会被解压缩并以原生位图格式存储在内存中。给定高度和宽度各 1500 像素,并假设位图格式为 32bpp(未指定时的默认值),您将看到 9MB 的已分配内存

    1500 * 1500 * 4 = 9MB。

    鉴于移动设备操作系统中存在的内存限制(32MB/进程 - 由系统 dll 分配的空间),您很可能处于内存紧缩情况。我当然不知道运行此代码的应用程序分配了哪些其他内存。

    在具有较小图像的同一设备上尝试相同的代码。您应该会看到它执行良好。

    【讨论】:

    • 哦,太好了,我在这里读到了一些关于它的东西link让我尝试使用较小的图像,但是没有办法做到这一点,我需要将图像传递给字节数组来存储它是一个数据库,实际上它可以在 PC 上运行(我猜是因为我可以滥用内存),但我在移动设备上遇到了这个问题。
    • 如果只需要将jpeg作为字节数组传递,为什么不直接使用FileStream对象从文件中读取字节数据而不是先解压缩为位图?
    • 可能是因为我不知道自己在做什么,好吧,让我试试,但同时你是对的,我刚刚用 400x400 图像进行了测试,但没有出现异常.
    【解决方案2】:

    您的泄漏 Gdi 句柄、将流和位图包装在 Using 子句中。

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    
        using ms As New IO.MemoryStream
            using bm As New Bitmap("\Application Data\imgs\IMG22.jpg")
                bm.Save(ms, Drawing.Imaging.ImageFormat.Jpeg)
            end using
        end using
    
    End Sub
    

    【讨论】:

    • 嗨@asawyer Oamm 我不太了解你,但即使包装流和位图(正如你向我展示的那样),应用程序在设备上运行时也会引发相同的异常。跨度>
    • @Allende pdriegen 可能是正确的,但这也可能有所贡献。
    • 嗨@asawyer,对不起,我没有粗鲁,但是如果我很好地理解用“使用”对象包装有助于释放资源,那么就像使用 .dispose()方法 ?还是我还是迷路了?
    • @Allende using 会将其转换为一个 try/finally 块,该块会自动为对象调用 Dispose()。运行时肯定会为您处理这些事情,但有时您需要尽快释放资源,例如在内存紧张的情况下。在 Windows 中,流和位图分配底层 OS 对象,如果您不调用 Dispose,这些对象在 GC 将来某个时间点拾取它们之前不会被释放。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-23
    • 2012-08-09
    • 2012-12-24
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多