简体   繁体   中英

TextureBrush Causes Memory Leak, Even If I Dispose It

I am working on a circular menu application.

Before I use a bitmap as background, I must crop it as a circle.

Well, I found a code snippet for cropping the picture C# crop circle in a image or bitmap or:

public System.Drawing.Image x(string sourceFile, int circleUpperLeftX, int circleUpperLeftY, int circleDiameter)
{
    Bitmap SourceImage = new Bitmap(System.Drawing.Image.FromFile(sourceFile));
    Rectangle CropRect = new Rectangle(circleUpperLeftX, circleUpperLeftY, circleDiameter, circleDiameter);
    Bitmap CroppedImage = SourceImage.Clone(CropRect, SourceImage.PixelFormat);
    TextureBrush TB = new TextureBrush(CroppedImage);
    Bitmap FinalImage = new Bitmap(circleDiameter, circleDiameter);
    Graphics G = Graphics.FromImage(FinalImage);
    G.FillEllipse(TB, 0, 0, circleDiameter, circleDiameter);
    return FinalImage;
}

But the code causes memory leak after a while in line 6.

Well, I tried adding TB.Dispose(); to prevent it but, that didn't help.

What should I do?

You need to dispose everything that implements IDispose , and looking at your code, it looks like:

SourceImage , CroppedImage , TB , G

FinalImage does not get disposed in this function since it is getting returned, but whatever is using FinalImage has the responsibility to dispose of it.

As PowerRoy mentioned, using blocks will take of the disposing for you.

Here is a refactored example using multiple using blocks:

public Image CreateFinalImage(string sourceFile, int circleUpperLeftX, int circleUpperLeftY, int circleDiameter) {
  Bitmap finalImage = new Bitmap(circleDiameter, circleDiameter);
  Rectangle cropRect = new Rectangle(circleUpperLeftX, circleUpperLeftY, circleDiameter, circleDiameter);

  using (Bitmap sourceImage = new Bitmap(System.Drawing.Image.FromFile(sourceFile)))
  using (Bitmap croppedImage = sourceImage.Clone(cropRect, sourceImage.PixelFormat))
  using (TextureBrush tb = new TextureBrush(croppedImage))
  using (Graphics g = Graphics.FromImage(finalImage)) {
    g.FillEllipse(tb, 0, 0, circleDiameter, circleDiameter);
  }

  return finalImage;
}

Hm... that appears to be a very inefficient way of clipping a bitmap. Here's how I'd do it:

public Image x(string sourceFile, int circleUpperLeftX, int circleUpperLeftY, int circleDiameter) {
    using(Bitmap sourceImage = new Bitmap(sourceFile), GraphicsPath p = new GraphicsPath()) {
        Bitmap destImage = new Bitmap(circleDiameter, circleDiameter, sourceImage.PixelFormat);

        p.AddEllipse(circleUpperLeftX, circleUpperLeftY, circleDiameter, circleDiameter);

        using(Graphics g = Graphics.FromImage(destImage)) {
            g.SetClip(p);
            g.DrawImageUnscaled(sourceImage, 0, 0);
        }

        return destImage;
    }
}

Right now, the reason for your memory leak is probably forgetting to dispose all those temporary Bitmap s. This method only creates two bitmaps and makes sure to dispose one of them, along with the Graphics object and the GraphicsPath used to create the mask.

Well, Solved It.

As you said, textbrush is not causing the memory leak.

I used to use this code:

pictureBox1.Image = menu.Draw(bos, new Point(Cursor.Position.X - Left, Cursor.Position.Y - Top), (int)DateTime.Now.Subtract(sabit).TotalMilliseconds / 4);

When I used this, I mean Disposing PictureBox's Image before assigning a new Bitmap to it prevented the memory leak.

Bitmap result = menu.Draw(bos, new Point(Cursor.Position.X - Left, Cursor.Position.Y - Top), (int)DateTime.Now.Subtract(sabit).TotalMilliseconds / 4);
        if (pictureBox1.Image != null)
            pictureBox1.Image.Dispose();
        pictureBox1.Image = (Image)result.Clone();
        result.Dispose();

Thank you all for your help!

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