使用control.BackgroundImage = Image.FromStream(memStream)时出现内存异常;

时间:2011-10-15 07:08:18

标签: c# winforms image exception

我编写了一个代码,用于从文件中读取png图像并显示控件 我想要从流中读取图像并设置

control.BackgroundImage = Image.FromStream(memStream);

但使用此代码时,会出现“内存不足”异常。但是在使用时

control.Image = Image.FromStream(memStream);

control.BackgroundImage = Image.FromFile(fileSource);

,这就是工作。

图片文件大小为5KB。

 if (System.IO.File.Exists(imgSource))
 {
  using (FileStream localFileStream = new FileStream(imgSource, FileMode.Open))
  {
  using (MemoryStream memStream = new MemoryStream())
  {
   int bytesRead;
   byte[] buffer = new byte[1024];

   while ((bytesRead = localFileStream.Read(buffer, 0, buffer.Length)) > 0)
   {
      memStream.Write(buffer, 0, bytesRead);
   }
   retIMG = Image.FromStream(memStream);

   pictureBox1.Image = retIMG;      // is work
   label1.Image = retIMG;       // is work
   button1.Image = retIMG;      // is work
   button1.BackgroundImage = retIMG;    // don't work
   groupBox1.BackgroundImage = retIMG;  // don't work
   panel1.BackgroundImage = retIMG; // don't work
  }
  }
 }

我认为.net框架中存在一个错误。 请你帮帮我?

3 个答案:

答案 0 :(得分:8)

阅读MSDNImage.FromStream上的评论:

  

您必须在图像的生命周期内保持流打开。

因此,如果您在创建using周围删除MemoryStream,则代码可以正常运行。

当你不再需要你创建的MemoryStream时,你应该优先处理Image,尽管在不调用Dispose()并留下它的情况下可能没有任何伤害到GC时,一旦未使用就收集它。

它似乎与你的一些代码一起使用的事实可能是纯粹的运气,不应被视为一个有效的解决方案。请务必阅读文档以了解有关这样的怪癖。

答案 1 :(得分:7)

给予一些背景以添加DeCaf的正确答案。 GDI +非常努力地避免复制位图的像素。这是昂贵的,占用几十兆字节的位图并不罕见。当您使用Bitmap构造函数或Image.FromFile()从文件加载位图时,GDI +会创建一个内存映射文件。仅在需要时才按需分页像素。效率很高但它会锁定文件。很明显,你试图避免锁定此代码。

您确实通过使用MemoryStream将字节加载到内存中来避免该锁定。但是同样的原则仍然适用,GDI +仍然不会复制像素,只在需要时从流中读取。 Dispose()流时会出错。很难诊断因为以后发生异常,通常需要绘制位图时。它在绘画代码中炸弹,你没有任何代码可以看,但Application.Run()。有了一个糟糕的异常消息,GDI +只有一些错误代码。你内存不足,它只能看到GDI +的方式,否则无法弄清楚为什么流突然不再可读了。

至少部分问题是由MemoryStream.Dispose()的非常笨拙的实现引起的。 Dispose旨在释放非托管资源。内存流没有任何内存流,它只拥有内存。这已经被垃圾收集器处理了。不幸的是他们无论如何实施了它不是通过实际处理任何东西,因为没有什么可以处理,而是通过标记MemoryStream不可读。在绘制位图时尝试读取时会触发GDI +中的错误。

因此,只需删除 using 语句,以避免处理MemoryStream来解决您的问题。并且不要担心以后在不再使用位图时将其处理掉。没有什么可以处理的,垃圾收集器会自动释放内存。

答案 2 :(得分:0)

两件事共同解决了这个间歇性问题,与图像大小无关。

首先,确保图像处于RGB模式,而绝对不是CMYK模式。根据我们的经验,RGB渲染实际上更大。

在加载新图像之前,第二次擦除(如果可能的话)图像容器中的任何先前图像,例如

Control.Image =没什么