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

g2s*_*sea 6 c# image exception winforms

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

control.BackgroundImage = Image.FromStream(memStream);
Run Code Online (Sandbox Code Playgroud)

但是当使用这段代码时,会发生"内存不足"异常.但是在使用时

control.Image = Image.FromStream(memStream);
Run Code Online (Sandbox Code Playgroud)

要么

control.BackgroundImage = Image.FromFile(fileSource);
Run Code Online (Sandbox Code Playgroud)

那就是工作.

图像文件大小为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
  }
  }
 }
Run Code Online (Sandbox Code Playgroud)

我认为.net框架中的一个错误.拜托你帮帮我?

DeC*_*Caf 8

阅读上的言论Image.FromStreamMSDN:

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

因此,如果你删除usingMemoryStream的代码创建周围工作正常.

当然,MemoryStream一旦你不再需要Image你创建的东西,你应该优先处理掉,尽管在这种情况下可能没有任何伤害,因为没有调用Dispose()并且一旦未使用就将其留给GC来收集它.

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


Han*_*ant 7

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

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

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

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