2

Here's my problem:

this method is repeated on a timertick of 50 ms. From the starting of the program to forward in time the RAM memory of this process grows continously and in the end the debugger throws me "out of memory error" to the line that is bolded (drawimage method).

Does anyone can help to me to find a solution to avoid this and explain me why this is happening?

PS. my goal is rotate a background image of a picturebox continously. I know that maybe I could draw directly on form rather than on a pictureBox, but if there is a solution for the pictureBox I will be happy :p

Thanks!

public static Bitmap RotateImage(Image image, PointF offset, float angle)
    {
        if (image == null)
            throw new ArgumentNullException("image");

        //create a new empty bitmap to hold rotated image
        Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
        rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        //make a graphics object from the empty bitmap
        Graphics g = Graphics.FromImage(rotatedBmp);

        //Put the rotation point in the center of the image
        g.TranslateTransform(offset.X, offset.Y);

        //rotate the image
        g.RotateTransform(angle);

        //move the image back
        g.TranslateTransform(-offset.X, -offset.Y);

        //draw passed in image onto graphics object
        **g.DrawImage(image, new PointF(0, 0));**

        return rotatedBmp;
    }
MrLore
  • 3,759
  • 2
  • 28
  • 36
Gasta87
  • 225
  • 5
  • 16

3 Answers3

2

You need to also Dispose() of the old bitmaps too.

Imagine your code looked like this:

public static Bitmap RotateImage(Image image, PointF offset, float angle)
{
    if (image == null)
        throw new ArgumentNullException("image");

    //create a new empty bitmap to hold rotated image
    Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
    rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
    return rotatedBmp;
}

I tried calling your function in a loop, and it still failed! I had to dispose of the bitmaps themselves. I am unclear why .NET doesn't clean them up.

Image img = new Bitmap(@"some_image.png");
PointF p = new PointF(0,0);
for (int i=0; i<5000; i++)
{
    Bitmap b = RotateImage(img, p, i % 360);
    b.Dispose(); // Fails if you don't do this!
}
Moby Disk
  • 3,761
  • 1
  • 19
  • 38
  • Of course, in your case you are presumably doing something with the bitmap, so you'll need to save the most recent one and discard it after generating the new one. – Moby Disk Jul 31 '14 at 17:54
1

Your graphics is never disposed, therefore you are leaking memory. I think you should dispose the graphic after drawing it,

g.Dispose()

Your should probably read a bit about Idisposable to avoid that problem in the future,

Christian Sauer
  • 10,351
  • 10
  • 53
  • 85
  • 2
    or use `using ( Graphics g = Graphics.FromImage(rotatedBmp)) ` – TaW Jul 31 '14 at 17:27
  • I thought that when the `Graphics` object went out of scope it would be automatically disposed... why is that not the case? – Jashaszun Jul 31 '14 at 17:28
  • It probably will dispose of it... eventually. But you are drawing so fast I don't think the Garbage collector can catch up! See also http://stackoverflow.com/questions/1572804/do-i-need-to-call-graphics-dispose – Moby Disk Jul 31 '14 at 17:29
  • I knew something about Idisposable, infact I've already tried both using and dispose... but didn't work! I thought that the graphic "g" was disposed by the end of the method rotate image! – Gasta87 Jul 31 '14 at 17:31
  • @MobyDisk I've raised the time to 500 ms instead 50 but still the memory is growing!!! why is that so? – Gasta87 Jul 31 '14 at 17:35
1

Here's the solution!!!

I've to dispose both backgroundimage of picturebox and the bitmap that I create each time!

Thanks to everyone!

    private void timer1_Tick(object sender, EventArgs e)
    {
        Image oldImage = RotateImage(
            pb_logoAfterLoad.BackgroundImage,
            offsetPoint,
            20);

        pb_logoAfterLoad.BackgroundImage.Dispose();
        pb_logoAfterLoad.BackgroundImage = (Image)oldImage.Clone();

        oldImage.Dispose();

    }
Gasta87
  • 225
  • 5
  • 16
  • Do you need to clone it? Can't you instead do: Image newImage = RotateImage(...); Image oldImage = pb_logoAfterLoad.BackgroundImage; pb_logoAfterLoad.BackgroundImage = newImage; oldImage.Dispose(); That avoids the copy. – Moby Disk Jul 31 '14 at 20:08