加载位图时出现内存不足错误

时间:2010-06-25 10:54:53

标签: c# .net exception bitmap out-of-memory

我正在使用大尺寸图像(例如16000x9440像素)并剪切一些区域以用于其他事物。我在创建一个新的Bitmap实例时遇到异常“Out of memory”:

using (FileStream fileStream = new FileStream(mapFileResized, FileMode.Open))
{
    byte[] data = new byte[fileStream.Length];
    fileStream.Read(data, 0, data.Length);
    using (MemoryStream memoryStream = new MemoryStream(data))
    {
        using (Bitmap src = new Bitmap(memoryStream)) // <-- exception
        {
            tile = new Bitmap(tileWidth, tileHeight, PixelFormat.Format24bppRgb);
            tile.SetResolution(src.HorizontalResolution, src.VerticalResolution);
            tile.MakeTransparent();
            using (Graphics grRect = Graphics.FromImage(tile))
            {
                grRect.CompositingQuality = CompositingQuality.HighQuality;
                grRect.SmoothingMode = SmoothingMode.HighQuality;
                grRect.DrawImage(
                        src,
                        new RectangleF(0, 0, tileWidth, tileHeight),
                        rTile,
                        GraphicsUnit.Pixel
                );
            }
        }
    }
}

当我使用小图像尺寸(例如8000x4720像素)时,一切正常。

如何处理大尺寸图像?

PS tile位图在finally块中处理。

最好的问候,Alex。

3 个答案:

答案 0 :(得分:6)

你正在使用大约一千兆字节的ram,并不是因为内存不足而感到非常惊讶。

假设您使用带有16000x9440像素的32bpp文件格式,您将获得大约的文件大小:

16000 * 9440 *(32/8)= ~576MB

byte[] data = new byte[fileStream.Length];
fileStream.Read(data, 0, data.Length);
using (MemoryStream memoryStream = new MemoryStream(data))
{
  [... snip ...]
}

您将整个文件加载到内存流中,这需要576MB。

[... snip ...]
    using (Bitmap src = new Bitmap(memoryStream)) // <-- exception
    {
        [... snip ...]
    }
[... snip ...]

您将整个流内容加载到位图中,这至少需要另外576MB(取决于每个像素位图需要多少内存,应该至少为4,可能更多)。那时你的内存中有两次图像会严重伤害这些大图像。

您可以通过删除内存流并直接从文件流加载位图来减少内存占用量。

另一个解决方案是只加载位图的一部分并按需加载其他部分(很像谷歌地图),但我无法帮助你解决这个问题,可能需要手动读取位图。

答案 1 :(得分:3)

对您的问题不是一个完整的答案,但您最好使用像ImageMagick.NET这样的库

答案 2 :(得分:2)

使用存储数据的字节数组实现

MemoryStream。如果您读取的数据多于数组可容纳的数据,则会分配一个新的double size数组,并将字节从一个数组复制到另一个数组。

由于您显然知道自己需要多少数据,因此可以预先分配正确的大小,从而避免调整大小。

但是,一旦达到一定的大小,就会耗尽内存。 .NET对单个对象(even on 64 bit)施加了2 GB的限制,因此MemoryStream中的内部数组永远不会超出该范围。如果您的图像大于该图像,则会出现内存不足异常。