【问题标题】:Out Of Memory exception on System.Drawing.Image.FromFile()System.Drawing.Image.FromFile() 上的内存不足异常
【发布时间】:2010-11-09 15:58:24
【问题描述】:

我有一个创建缩略图的图像上传器和裁剪器,我偶尔会在以下行中遇到内存不足异常:

Dim bm As Bitmap = System.Drawing.Image.FromFile(imageFile)

错误的发生很小且非常罕见,但我总是想知道可能导致它的原因。 imageFile 变量只是图像路径的 Server.MapPath。

我很好奇以前是否有人遇到过这个问题,他们是否知道可能是什么原因造成的?可能是图片的大小吗?

如有必要,我可以发布代码以及我拥有的任何支持信息,但很想听听人们对此的意见。

【问题讨论】:

  • 您要加载的图片是否特别大?
  • 所有图片小于~700kb。
  • 您确定该文件是有效的图像文件吗?我也遇到了完全相同的情况,但是该文件也无法在任何其他程序中加载。
  • 我非常感谢您的回复。这不是我的图像,所以我将其发送过来并进行检查。上传的人特别无能,所以我希望就是这样!
  • 好的,图片已损坏。问题解决了。多谢你们。丹比,如果您添加答案,我会将其标记为正确;)

标签: asp.net image bitmap


【解决方案1】:

值得了解的是,OutOfMemoryException 并不总是真的意味着内存不足——尤其是在处理文件时。我相信如果您出于某种原因用完句柄也会发生这种情况。

您是否在处理完所有位图后将其丢弃?对于单个图像,这种情况是否会重复发生?

【讨论】:

  • 您好乔恩,感谢您的快速回复。是的,我处理了图像和图形。 Dim bmPhoto As New Bitmap(targetW, targetH, PixelFormat.Format24bppRgb) Dim grPhoto As Graphics = Graphics.FromImage(bmPhoto) bmPhoto.Dispose() bmPhoto = Nothing grPhoto.Dispose() grPhoto = Nothing 至于可重复性,不是非常随机 - 但图像总是倾向于更大(尽管不超过 700k~)。
  • 我怀疑它可能不是文件大小,而是内存中的图像大小 - 具有大量像素的高度压缩图像可能会导致您出现问题...
  • 您好乔恩,感谢您的评论。原来是一直损坏的图像。 叹气。一个不称职的用户。不过感谢您的回答:)
  • 您如何确定图像已损坏?在执行 Image.FromFile 时,我也遇到了这些 OutOfMemoryException 错误。奇怪的是它只在一台服务器上抛出异常,而不是在另一台服务器上抛出异常。我会错过一些重要的编码器吗?这是从 Getty 图像下载的 4256x2832 24bpp sRGB JPEG。
  • 嘿,马克,我只是尝试直接通过操作系统打开图像。它无法打开它。 Photoshop 或任何其他图像软件也不能。这导致了抛出。
【解决方案2】:

如果这不是错误的图像文件,但实际上是 Image.FromFile 的正常问题,其中文件句柄处于打开状态,那么解决方案是改用 Image.FromStream

using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
   using (Image original = Image.FromStream(fs))
   {
      ...

使用显式Dispose()using() 语句或在位图上将值设置为null 并不能解决Image.FromFile 的问题。

因此,如果您的 App 运行一段时间并打开大量文件,请考虑改用 Image.FromStream()

【讨论】:

  • 实际上,如果您通过非托管句柄处置绑定到文件的流,则该句柄将在那里关闭,然后根本不等待GC发生。毕竟,这就是 IDisposable 的全部意义所在。
  • 这也可以更进一步。 blogs.msdn.com/b/omars/archive/2004/03/29/100941.aspx,似乎仍然适用。
  • 在这种情况下,带有 alpha 的 pdf 怎么样?
  • 为什么调用 Dispose() 不释放图像的文件句柄?这只是实现中的一个错误吗?为什么微软从未修复此错误?显然,出于多种原因,使用流更好,但微软似乎应该修复这个问题或完全删除该方法。
【解决方案3】:

你也可以在阅读模式下打开它,(如果你想同时在两个地方使用它)

 public Image OpenImage(string previewFile)
        {
            FileStream fs = new FileStream(previewFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            return Image.FromStream(fs);
        }

【讨论】:

    【解决方案4】:

    我今天尝试调整图像大小然后裁剪它时遇到了类似的问题,发生的事情是我使用此代码调整图像大小。

    private static Image resizeImage(Image imgToResize, Size size)
    {
       int sourceWidth = imgToResize.Width;
       int sourceHeight = imgToResize.Height;
    
       float nPercent = 0;
       float nPercentW = 0;
       float nPercentH = 0;
    
       nPercentW = ((float)size.Width / (float)sourceWidth);
       nPercentH = ((float)size.Height / (float)sourceHeight);
    
       if (nPercentH < nPercentW)
          nPercent = nPercentH;
       else
          nPercent = nPercentW;
    
       int destWidth = (int)(sourceWidth * nPercent);
       int destHeight = (int)(sourceHeight * nPercent);
    
       Bitmap b = new Bitmap(destWidth, destHeight);
       Graphics g = Graphics.FromImage((Image)b);
       g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    
       g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
       g.Dispose();
    
       return (Image)b;
    }
    

    然后是作物的这段代码......

    private static Image cropImage(Image img, Rectangle cropArea)
    {
       Bitmap bmpImage = new Bitmap(img);
       Bitmap bmpCrop = bmpImage.Clone(cropArea,
       bmpImage.PixelFormat);
       return (Image)(bmpCrop);
    }
    

    那我就是这样调用上面的代码的……

    Image img = Image.FromFile(@"C:\Users\****\Pictures\image.jpg");
    img = ImageHandler.ResizeImage(img, new Size(400, 300));
    img = ImageHandler.CropImage(img, new Rectangle(0, 25, 400, 250));
    long quality = 90;
    

    我一直在裁剪部分出错,调整大小工作正常!

    事实证明,调整器内部发生的事情是在裁剪功能中引发错误。调整大小的计算使图像的实际尺寸变成了 399 而不是我传入的 400。

    所以,当我传入 400 作为裁剪的参数时,它试图用 400 像素宽度的 bmp 裁剪 399 像素宽的图像,并抛出内存不足错误!

    以上代码大部分是在http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing上找到的

    【讨论】:

      【解决方案5】:

      我今天在为一个充满图像的文件夹创建缩略图图像时遇到了同样的问题。事实证明,“Out Of Memory”每次都恰好发生在同一点。当我查看包含要转换的图像的文件夹时,我发现导致问题的文件是 thumbs.db。我添加了一些代码以确保只转换图像文件并解决了问题。

      我的代码基本上是

      For Each imageFile as FileInfo in fileList
      If imageFile.Extension = ".jpg" Or imageFile.Extension = ".gif" Then
          ...proceed with the conversion
      End If
      Next
      

      希望这会有所帮助。

      【讨论】:

      • 是的,未处理的图像类型被抛出为 OOM。每次都能吸引我。
      【解决方案6】:

      我在批处理 Tiff 文件时遇到了同样的问题。大多数文件没有引发异常,但在 ASP.NET 4.0 中很少有文件引发“内存不足”异常。我已经使用二进制数据来找出为什么只针对少数文件和来自同一文件夹的原因。这不可能是 ASP.NET ASPNET 或 NETWORK SERVICE 帐户的权限问题,因为其他文件是工作文件。

      我打开了iTextSharp.text.Image类,发现GetInstance()有很多重载方法。我已经使用以下代码解决了我的问题:注意:catch 块将对有问题的文件运行。

                      iTextSharp.text.Image image = null;
                  try
                      {
                          var imgStream = GetImageStream(path);
                           image = iTextSharp.text.Image.GetInstance(imgStream);
                      }
                      catch {
                          iTextSharp.text.pdf.RandomAccessFileOrArray ra = null;
                          ra = new iTextSharp.text.pdf.RandomAccessFileOrArray(path);
                          image = iTextSharp.text.pdf.codec.TiffImage.GetTiffImage(ra, 1);
      
                          if (ra != null)
                              ra.Close();
      
                      }
      

      【讨论】:

      • 在这种情况下 GetImageStream(path) 方法在哪里?一旦有了 iTextSharp.text.Image 的图像对象,如何将其转换为 System.Drawing.Image 对象?
      【解决方案7】:

      如果图像是图标,则需要不同的加载处理,例如在下一个函数中:

      public static Image loadImage(string imagePath)
          {
              Image loadedImage = null;
              if (!File.Exists(imagePath)) return loadedImage;
              try
              {
                  FileInfo fileInfo = new FileInfo(imagePath);
                  if (fileInfo.Extension.Equals(".jpg") || fileInfo.Extension.Equals(".jpeg") ||
                     fileInfo.Extension.Equals(".bmp") || fileInfo.Extension.Equals(".png") ||
                     fileInfo.Extension.Equals(".gif"))
                  {
                      loadedImage = Image.FromFile(imagePath);
                  }
                  else if (fileInfo.Extension.Equals(".ico"))
                  {
                      Bitmap aBitmap = Bitmap.FromHicon(new
                                                 Icon(imagePath, new Size(200, 200)).Handle);
                      loadedImage = ImageFuncs.ResizeImage(aBitmap, new Size(30, 30));
                  }
              }
              catch (Exception eLocal)
              {
                  MessageBox.Show(imagePath + " loading error: " + eLocal.Message);
              }
              return loadedImage;
          }
      

      【讨论】:

        【解决方案8】:

        我编写的将 TIFF 转换为 PDF 的实用程序遇到了同样的问题。我经常会和你在同一行收到“内存不足”错误。

        System.Drawing.Image.FromFile(imageFile)
        

        然后我发现这个错误只发生在文件扩展名是“.tiff”并且在我用扩展名“.tif”重命名它之后工作正常

        【讨论】:

          【解决方案9】:

          还要检查您是否没有在其他地方打开过相同的文件。显然,当您打开文件两次时(即使使用 File.Open())也会抛出 OutOfMemoryException ...

          【讨论】:

            【解决方案10】:

            我遇到了同样的问题,在查看代码中的其他位置之前,我想确保我是否可以使用任何图像查看器打开图像并发现图像已损坏/损坏,尽管它是一个大小为 1KB 的 .PNG 文件.在同一位置添加了一个新图像,然后它工作正常。

            【讨论】:

              【解决方案11】:

              当图像文件损坏时会发生这种情况。这是一个糟糕的错误消息,因为内存与它无关。我还没有编写出代码,但是 try/catch/finally 会阻止程序异常结束。

              【讨论】:

                【解决方案12】:

                如果您从 IIS 提供服务,请尝试回收应用程序池。这为我解决了类似的图片上传“内存不足”错误。

                【讨论】:

                • 我在尝试了很多事情之后做了这个 - 从图像中剥离元数据,在上传之前重命名文件,上传到系统的另一部分,上传一个简单的(和更小的图像) - 都没有成功,在成功上传原图之前尝试了上述回收。
                【解决方案13】:

                我创建了一个仍然给我错误的最小表单示例。

                        private void button1_Click(object sender, EventArgs e)
                    {
                        string SourceFolder = ImageFolderTextBox.Text;
                        string FileName = "";
                        DirectoryInfo Mydir = new DirectoryInfo(SourceFolder);
                        FileInfo[] JPEGS = Mydir.GetFiles("*.jpg");
                        for (int counter = 0; counter < JPEGS.Count(); counter++)
                        {
                            FileName = Mydir + "\\" + JPEGS[counter].Name;
                            //using (Image MyImage = System.Drawing.Image.FromFile(FileName))
                            using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                            {
                                StatusBtn.BackColor = Color.Green;
                            }
                        }
                    }
                

                我尝试了使用 Image.FromFile() 的注释行以及使用 FileStream() 的行。两者都产生了文件错误。

                Image.FromFile() 错误是: System.OutOfMemoryException: '内存不足'

                filestream() 错误是: System.UnaurthorizedAccessException: '访问路径'E:\DCIM\100Canon\dsc_7218.jpg' 被拒绝。

                我在产生错误的行之前放置了一个断点,我可以使用 Windows 图像查看器打开图像文件。然后我关闭了查看器,在进入下一行并收到错误消息后,我无法再使用 Windows 查看器查看图像。相反,我收到一条消息,指出我无权访问该文件。我可以删除文件。

                此错误是可重复的。我已经做了10多次了。每次收到错误后,我都会删除用于 FileName 的文件。

                所有文件都经过验证没有损坏。

                我使用 Image.FromFile() 的原始代码在 2 年前编译时运行良好。事实上,.exe 文件运行得很好。我在代码的其他地方做了一个小的改动,惊讶地发现如果没有这个错误代码就无法编译。我根据这个页面上的信息尝试了 FileStream() 方法。

                【讨论】:

                  猜你喜欢
                  • 2015-09-28
                  • 2010-10-05
                  • 1970-01-01
                  相关资源
                  最近更新 更多