C# Bitmap/Graphics Out of Memory

2020-05-01 15:43发布

I'm trying to take a snapshot of the whole screen for reading pixel values. Actually i'm doing it without any problem. But after exactly 214 snapshots, i'm getting out of memory exception.

Bitmap ScreenShot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
  Screen.PrimaryScreen.Bounds.Height);

public Bitmap TakeSnapshot()
{
    Graphics graphic = null;
    Rectangle rect = new Rectangle(0, 0, Screen.PrimaryScreen.Bounds.Width,
      Screen.PrimaryScreen.Bounds.Height);

    using (graphic = Graphics.FromImage(ScreenShot))
    {
        graphic.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 
            0, 0, 
            ScreenShot.Size, 
            CopyPixelOperation.SourceCopy);
    }

    return ScreenShot.Clone(rect,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
}

I'm using this method with timer

Bitmap bmp = TakeSnapshot();
        var c = bmp.GetPixel(0,0);

It was giving invalid parameter exception. I solved it with "using". But now i'm stuck on this exception.

1条回答
聊天终结者
2楼-- · 2020-05-01 16:26

You need to dispose disposable resources once you're done working with them. Bitmap class implements IDisposable - so it is disposable resource. Correct pattern is instead of

Bitmap bmp = TakeSnapshot();
var c = bmp.GetPixel(0,0);

Something like

Bitmap bmp = null;
try
{
  bmp = TakeSnapshot();
  var c = bmp.GetPixel(0,0);
  // any more work with bmp
}
finally
{
  if (bmp != null)
  {
    bmp.Dipose();    
  }
}

Or in short form (which is preferable):

using(Bitmap bmp = TakeSnapshot())
{
  var c = bmp.GetPixel(0,0);
  // any more work with bmp
}

Reference: Using Objects That Implement IDisposable

Edit

You can easily emulate the issue:

public class TestDispose : IDisposable
{
    private IntPtr m_Chunk;
    private int m_Counter;
    private static int s_Counter;

    public TestDispose()
    {
        m_Counter = s_Counter++;
        // get 256 MB
        m_Chunk = Marshal.AllocHGlobal(1024 * 1024 * 256);
        Debug.WriteLine("TestDispose {0} constructor called.", m_Counter);
    }

    public void Dispose()
    {
        Debug.WriteLine("TestDispose {0} dispose called.", m_Counter);
        Marshal.FreeHGlobal(m_Chunk);
        m_Chunk = IntPtr.Zero;
    }
}

class Program
{
    static void Main(string[] args)
    {
        for(var i = 0; i < 1000; i ++)
        {
            var foo = new TestDispose();
        }
        Console.WriteLine("Press any key to end...");
        Console.In.ReadLine();
    }
}
查看更多
登录 后发表回答