2016-06-29 4 views
0

Я пытаюсь сделать снимок всего экрана для чтения значений пикселей. На самом деле я делаю это без проблем. Но после 214 снимков я получаю исключение из памяти.C# Bitmap/Graphics Out of Memory

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); 
} 

Я использую этот метод с таймером

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

Он дает недопустимое исключение параметра. Я решил это с помощью «использования». Но теперь я застрял на этом исключении.

+1

Похоже, вы используете 32-разрядный процесс и выскабливание предела 2GB. Зачем вам все эти снимки в памяти? Уберите те, которые вам больше не нужны. – Rotem

+0

Сходства: http://stackoverflow.com/questions/4318563/c-sharp-out-of-memory-when-creating-bitmap –

+1

Вы удаляете Bitmap самостоятельно после того, как закончите работать с ним? –

ответ

1

После того, как вы закончите работу с ними, вам нужно будет располагать одноразовые ресурсы. Bitmap класс реализует IDisposable - так что это одноразовый ресурс. Правильная картина вместо

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

Нечто подобное

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

Или в краткой форме (что является предпочтительным):

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

Ссылка: Using Objects That Implement IDisposable

Edit

Вы можете легко эмулировать вопрос:

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(); 
    } 
} 
+0

Если 'Bitmap' правильно реализует IDisposable, не должен ли он распоряжаться собой, когда ссылок больше нет? По крайней мере, если он будет следовать описанной здесь логике деструктора: http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface –

+0

@Thomas - вы прочитали принятый ответ? :) Сборщик мусора освобождает ТОЛЬКО управляемые ресурсы - поэтому, если вы ссылаетесь на неуправляемую память (и класс Bitmap делает это), выделенная неуправляемая память останется выделенной до конца процесса. –

+0

Нет, посмотрите на 'protected void Dispose (Boolean itIsSafeToAlsoFreeManagedObjects)': он всегда освобождает неуправляемые ресурсы. –