简体   繁体   中英

Memory leaks looping through images to byte arrays

I have a routine that scans a folder for images, then for each image, converts it to a thumbnail, and then uploads that thumbnail to a database. It will only run if there isn't any items for that particular folder in the db. My problem is I am receiving an out of memory exception after processing a couple of folders and I'm not sure where the leak is occurring. I have tried disposing of everything disposable that I can in the loop, but obviously something is still falling though the cracks.

private bool LoadImages(int folderid, int parentid) {
  ProgressScreen tfrm = new ProgressScreen();
  tfrm.Hide();
  DataTable mtable = new DataTable();
  List<FileInfo> lfile;
  mtable = Requests.ProcessSQLCommand(sqlconn, "Select f.ID, f.FolderName,f.FolderPath,f.ParentID,f.Root from Folders f where f.ID = " + folderid);
  DataTable ptable = Requests.ProcessSQLCommand(sqlconn, "Select Root from Folders where ID = " + parentid);
  if (ptable != null && ptable.Rows.Count > 0) {
    if (ptable.Rows[0]["Root"].ToString().ToLower() == "true") {
      return false;
    }
  }
  bool process = true;
  DirectoryInfo di = new DirectoryInfo(mtable.Rows[0]["FolderPath"].ToString());
  FileInfo[] smFiles = di.GetFiles("*.jpg", SearchOption.TopDirectoryOnly);
  lfile = smFiles.ToList<FileInfo>();
  if (lfile.Count <= 0) {
    process = false;
  }
  if (process) {
    tfrm.Show(this);
    for (int c = 0; c < lfile.Count; c++) {
      if (((FileInfo)lfile[c]).Extension == ".txt") {
        lfile.RemoveAt(c);
      }
      if (((FileInfo)lfile[c]).FullName.ToLower().Contains("cover")) {
        lfile.RemoveAt(c);
      }
    }
      for (int b = 0; b < lfile.Count; b++) {
        Cursor.Current = Cursors.WaitCursor;
        this.Enabled = false;
        try {
          tfrm.Location = new Point((Screen.PrimaryScreen.WorkingArea.Width / 2) - (tfrm.Width / 2), (Screen.PrimaryScreen.WorkingArea.Height / 2) - (tfrm.Height / 2));
        } catch {
        }
        tfrm.SetProgress((int)(((double)(b + 1) / (double)lfile.Count) * 100), "Loading Images", lfile[b].Name.ToString());
        tfrm.Refresh();
        int recid = 0;
        DataTable ttable = Requests.ProcessSQLCommand(sqlconn, "Insert into Image (Name,FolderID,ParentID) VALUES ('" + lfile[b].Name + "'," + folderid + "," + parentid + ") Select SCOPE_IDENTITY()");
        if (ttable != null && ttable.Rows.Count > 0) {
          recid = int.Parse(ttable.Rows[0][0].ToString());
        }
        if (recid > 0) {
          Image timg = null;
          byte[] traw = new byte[0];
          traw = File.ReadAllBytes(lfile[b].FullName);
          MemoryStream tstream = new MemoryStream(traw);
          timg = System.Drawing.Image.FromStream(tstream);
          tstream.Dispose();
          timg = Requests.FixedSize(timg, 600, 600);
          tstream = new MemoryStream();
          timg.Save(tstream, System.Drawing.Imaging.ImageFormat.Png);
          timg.Dispose();
          traw = new byte[0];
          traw = tstream.ToArray();
          tstream.Dispose();
          System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(sqlconn);
          con.Open();
          System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("Update Image set [Thumb] = Convert(VarBinary(MAX),@Image) where ID = " + recid, con);
          cmd.Parameters.AddWithValue("@Image", traw);
          cmd.ExecuteNonQuery();
          con.Dispose();
        }
      }
    this.Enabled = true;
    Cursor.Current = Cursors.Default;
    tfrm.Close();
    tfrm.Dispose();
    System.Windows.Forms.Application.UseWaitCursor = false;
    return true;
  } else {
    return false;
  }
}

the Fixed size method:

public static Image FixedSize(Image imgPhoto, int Width, int Height) {
  int sourceWidth = imgPhoto.Width;
  int sourceHeight = imgPhoto.Height;
  int sourceX = 0;
  int sourceY = 0;
  int destX = 0;
  int destY = 0;

  float nPercent = 0;
  float nPercentW = 0;
  float nPercentH = 0;

  nPercentW = ((float)Width / (float)sourceWidth);
  nPercentH = ((float)Height / (float)sourceHeight);
  if (nPercentH < nPercentW) {
    nPercent = nPercentH;
    destX = System.Convert.ToInt16((Width - (sourceWidth * nPercent)) / 2);
  } else {
    nPercent = nPercentW;
    destY = System.Convert.ToInt16((Height - (sourceHeight * nPercent)) / 2);
  }

  int destWidth = (int)(sourceWidth * nPercent);
  int destHeight = (int)(sourceHeight * nPercent);

  Bitmap bmPhoto = new Bitmap(Width, Height, PixelFormat.Format24bppRgb);
  bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

  Graphics grPhoto = Graphics.FromImage(bmPhoto);
  grPhoto.Clear(Color.Magenta);
  grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
  grPhoto.DrawImage(imgPhoto, new Rectangle(destX, destY, destWidth, destHeight), new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), GraphicsUnit.Pixel);

  grPhoto.Dispose();
  return bmPhoto;
}

the original images (before fixed size) range anywhere from 2MB to 20MB, the image returned (max(len(image)) in the table is around 750 KB. (Edit: Corrected files sizes)

Number of images per folder ~100-150

I've looked and debugged, but cannot find what is causing the OOM issues, could someone point me at the error, or offer a better optimization for what I am doing?

If this was a code review, there would be many things I'd suggest as improvements in this code... But anyway, specifically to your question.. you memory leak is in following lines of code (please don't take it personally, but it was hard to spot, because the code is not as clean)

      timg = System.Drawing.Image.FromStream(tstream);
      tstream.Dispose();
      timg = Requests.FixedSize(timg, 600, 600);
      ....
      timg.Dispose();

You have 2 timg here.. one is original, and the second one is the one you get back from Requests.FixedSize . The timg you passed to Requests.FixedSize does not get disposed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM