【问题标题】:System OutOfMemory But I am not saving anything so how?System OutOfMemory 但我没有保存任何东西,那怎么办?
【发布时间】:2017-02-28 16:52:22
【问题描述】:

运行我的 C# 控制台应用程序时遇到一个奇怪的错误。

//get trainingimages
var trainingImages = Directory.GetFiles(
   "C:\\Users\\tub08918\\Google Drive\\Patil Lab\\AlexsFolderPleaseVisitMe\\ISIC-2017_Training_Data\\ISIC-2017_Training_Data",
   "*.jpg"
).ToList();

for (var i = 0; i < trainingImages.Count; i++)
{
   var image = Image.FromFile(trainingImages[i]);
   var vsImage = ConvertBitmap(new Bitmap(image));

   //cnvert to 2d array
   var imgArray = new int[vsImage.Width, vsImage.Height, 3];

   for (var j = 0; j < vsImage.Width; j++)
      for (var z = 0; z < vsImage.Height; z++)
      {
         var p = vsImage.GetPixel(j, z);
         imgArray[j, z, 0] = p.R;
         imgArray[j, z, 1] = p.G;
         imgArray[j, z, 2] = p.B;
      }
}

我得到运行时异常:

System.Drawing.dll 中出现“System.OutOfMemoryException”类型的未处理异常

附加信息:内存不足。

但我是逐个图像地做这个,所以我很困惑我的逻辑的哪些部分有问题。我的转换位图函数如下所示:

public static Bitmap ConvertBitmap(Bitmap image)
{
   // Convert other formats (including CMYK) to RGB.
   var newImage = new Bitmap(newWidth, newHeight);

   // Draws the image in the specified size with quality mode set to HighQuality
   using (var graphics = Graphics.FromImage(newImage))
   {
      graphics.DrawImage(image, 0, 0, newWidth, newHeight);
   }

   return newImage;
}

【问题讨论】:

  • 奇怪?我会说,这段代码预计会发生这种情况。建造一次性物品而不处置它们。用所有图像中的所有字节填充数组,如果有很多图像,这可能会占用大量内存。
  • 嗯,我认为每当我退出循环时都会被处理掉。那么我将如何处理每张图片?
  • 该错误可能表明您正在访问图像边界之外的内存位置。我将首先验证图像的宽度和高度是否有效。这些数字应该是标准图像尺寸。
  • “但我没有保存任何东西,所以如何”。 “内存”是指 RAM,而不是硬盘空间。这将取决于您拥有多少张大小的图像。 100 张 1000x1000 图像会消耗 100*1000*1000*3*4 = 1.2GB 的 RAM。 (这只是你的数组)。
  • @woofwoof 要么使用using(那么一次性对象将在 using-block 的末尾进行处理)或手动处理对象。

标签: c#


【解决方案1】:

请记住,内存不足异常可能是因为您已用完图形对象的句柄,而不仅仅是普通的旧 RAM。

您需要处理掉每个IDisposable。在您的代码中,您需要为循环的每次迭代处理三个对象。

您的代码应如下所示:

//get trainingimages
var trainingImages = Directory.GetFiles(
   "C:\\Users\\tub08918\\Google Drive\\Patil Lab\\AlexsFolderPleaseVisitMe\\ISIC-2017_Training_Data\\ISIC-2017_Training_Data",
   "*.jpg"
).ToList();

for (var i = 0; i < trainingImages.Count; i++)
{
    using (var image = Image.FromFile(trainingImages[i]))
    {
        using (var bm = new Bitmap(image))
        {
            using (var vsImage = ConvertBitmap(bm))
            {
                var imgArray = new int[vsImage.Width, vsImage.Height, 3];
                for (var j = 0; j < vsImage.Width; j++)
                {
                    for (var z = 0; z < vsImage.Height; z++)
                    {
                        var p = vsImage.GetPixel(j, z);
                        imgArray[j, z, 0] = p.R;
                        imgArray[j, z, 1] = p.G;
                        imgArray[j, z, 2] = p.B;
                    }
                }
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    在我的一个应用中遇到了同样的问题。调用 FromFile 方法时使用using。 而不是:

     var image = Image.FromFile(trainingImages[i]);
    

    用途:

    using (var image = Image.FromFile(trainingImages[i]))
    {
        using (var bitmap = new Bitmap(image))
        {
            using (var vsImage = ConvertBitmap(bitmap))
            {
                //cnvert to 2d array
                var imgArray = new int[vsImage.Width, vsImage.Height, 3];
    
                for (var j = 0; j < vsImage.Width; j++)
                    for (var z = 0; z < vsImage.Height; z++)
                    {
                        var p = vsImage.GetPixel(j, z);
                        imgArray[j, z, 0] = p.R;
                        imgArray[j, z, 1] = p.G;
                        imgArray[j, z, 2] = p.B;
                    }
            }
        }
    }
    

    这就是为什么会出现 OutOfMemory 异常,因为 Image 对象没有被释放或者它们被释放得太晚。

    【讨论】:

    • var vsImage = ConvertBitmap(new Bitmap(image)); 需要两个 using(){} 块。
    猜你喜欢
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 2020-04-09
    相关资源
    最近更新 更多