.net - Control.Invalidate() use too much RAM. Optimization of C# WinForms drawing - Stack Overflow

admin2025-04-16  6

I'm developing one game on WinForms on C# and i have a rotating drum of a revolver with cartridges. But my programm use over 2GB RAM. This is crazy. Even if i remove all code from OnPaint situation doesn't become much better. Probably exists smth another ways to update graphics

Spining logic:

int spinTimes = Global.rand.Next(12, 24);
int n = spinTimes * 20;
int mod = n / 25;
int delay = 10;
Thread spiningThread = new Thread(() =>
{
    for (int i = 0; i < n; i++)
    {
        if (i % mod == 0)
        {
            delay += 1;
        }
        if (wheelAngle + 3 < 360)
        {
            wheelAngle += 3;
        }
        else
        {
            wheelAngle = 3;
        }
        pictureBox1.Invalidate();
        Thread.Sleep(delay);
    }
});
spiningThread.Start();

OnPaint of pictureBox1:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;

    shots[] shots_arr = wheel.get();

    Point center = new Point(pictureBox1.Width / 2, pictureBox1.Height / 2);
    g.TranslateTransform(center.X, center.Y);
    g.RotateTransform(wheelAngle);
    g.TranslateTransform(-center.X, -center.Y);

    g.DrawImage(Image.FromFile("Images/wheel.png"),10,10,pictureBox1.Width - 15,pictureBox1.Height - 15);

    for(int i = 0; i < 6; i++) {
        Image image = null;
        switch (shots_arr[i])
        {
            case shots.EMPTY:
                {
                    image = Image.FromFile("Images/shot_empty.png");
                    break;
                }
            case shots.FULL:
                {
                    image = Image.FromFile("Images/shot_full.png");
                    break;
                }
        }
        if (image == null) { break; }
        g.DrawImage(image, shots_xy[i]);
    }
}

I'm developing one game on WinForms on C# and i have a rotating drum of a revolver with cartridges. But my programm use over 2GB RAM. This is crazy. Even if i remove all code from OnPaint situation doesn't become much better. Probably exists smth another ways to update graphics

Spining logic:

int spinTimes = Global.rand.Next(12, 24);
int n = spinTimes * 20;
int mod = n / 25;
int delay = 10;
Thread spiningThread = new Thread(() =>
{
    for (int i = 0; i < n; i++)
    {
        if (i % mod == 0)
        {
            delay += 1;
        }
        if (wheelAngle + 3 < 360)
        {
            wheelAngle += 3;
        }
        else
        {
            wheelAngle = 3;
        }
        pictureBox1.Invalidate();
        Thread.Sleep(delay);
    }
});
spiningThread.Start();

OnPaint of pictureBox1:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;

    shots[] shots_arr = wheel.get();

    Point center = new Point(pictureBox1.Width / 2, pictureBox1.Height / 2);
    g.TranslateTransform(center.X, center.Y);
    g.RotateTransform(wheelAngle);
    g.TranslateTransform(-center.X, -center.Y);

    g.DrawImage(Image.FromFile("Images/wheel.png"),10,10,pictureBox1.Width - 15,pictureBox1.Height - 15);

    for(int i = 0; i < 6; i++) {
        Image image = null;
        switch (shots_arr[i])
        {
            case shots.EMPTY:
                {
                    image = Image.FromFile("Images/shot_empty.png");
                    break;
                }
            case shots.FULL:
                {
                    image = Image.FromFile("Images/shot_full.png");
                    break;
                }
        }
        if (image == null) { break; }
        g.DrawImage(image, shots_xy[i]);
    }
}
Share Improve this question edited Feb 4 at 0:49 Charlieface 73.4k8 gold badges33 silver badges64 bronze badges asked Feb 3 at 23:05 BoblikutBoblikut 73 bronze badges 14
  • 2 You're trying to load seven images from disk every 10ms. You're probably not achieving that kind of frame rate, but even at 50Hz that's a lot of memory. – Corey Commented Feb 3 at 23:18
  • Main issue here is using PictureBox. This is not a bitmap itself, this is a totally redundant control used for simplification of already simplest chores, such as showing a static bitmap. And even for this purpose, it is redundant. The second issue is: the bitmap-based techniques, no matter how well optimized, are totally unsuitable for animation or other dynamic imaging. The only reasonable solution is to give up the idea and do something else. – Sergey A Kryukov Commented Feb 3 at 23:41
  • 1 WinForms is not a game engine. In any case, you really need to avoid loading the same images from file in the Paint event, without disposing of any of them. Load the images beforehand, then reuse those bitmaps. Dispose of them when the Form closes, if it's not the main Form – Jimi Commented Feb 3 at 23:46
  • 4 Main issue here is using PictureBox. I actually think the main issue is not PictureBox. It is that Image.FromFile is called repeatedly, and the Images returned are not being disposed. If those Image.FromFile calls were assigned to fields then the memory usage will drop massively (if there is only one copy of each, don't bother disposing them). – mjwills Commented Feb 4 at 0:11
  • 1 Image.FromFile at 100 fps without Dispose is going to hit a high watermark for RAM pretty quickly. – Wyck Commented Feb 4 at 2:16
 |  Show 9 more comments

1 Answer 1

Reset to default 2

Your issue is you are creating these Image objects and not disposing them. But to be honest, you may as well just cache them.

You can simplify the switch as well.

private static Image _wheelImage = Image.FromFile("Images/wheel.png");
private static Image _emptyImage = Image.FromFile("Images/shot_empty.png");
private static Image _fullImage = Image.FromFile("Images/shot_full.png");

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;

    shots[] shots_arr = wheel.get();

    Point center = new Point(pictureBox1.Width / 2, pictureBox1.Height / 2);
    g.TranslateTransform(center.X, center.Y);
    g.RotateTransform(wheelAngle);
    g.TranslateTransform(-center.X, -center.Y);

    g.DrawImage(_wheelImage, 10, 10, pictureBox1.Width - 15, pictureBox1.Height - 15);

    for (int i = 0; i < 6; i++)
    {
        Image image = shots_arr[i] switch
        {
            shots.EMPTY => _emptyImage,
            shots.FULL => _fullImage,
            _ => null,
        };
        if (image == null)
            break;

        g.DrawImage(image, shots_xy[i]);
    }
}
转载请注明原文地址:http://www.anycun.com/QandA/1744746309a87024.html