2016-06-29 25 views
0

Ich versuche einen Schnappschuss des gesamten Bildschirms zum Lesen von Pixelwerten zu erstellen. Eigentlich mache ich das ohne Probleme. Aber nach genau 214 Snapshots bekomme ich eine Ausnahme vom Speicher.C# Bitmap/Grafikspeicher

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

Ich benutze diese Methode mit Timer

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

Es wurde ungültiger Parameter Ausnahme geben. Ich habe es mit "using" gelöst. Aber jetzt bin ich auf dieser Ausnahme fest.

+1

Klingt wie Sie ein 32-Bit-Prozess und Abkratzen der 2 GB Grenze laufen. Warum brauchen Sie all diese Snapshots zusammen im Speicher? Entsorge diejenigen, die du nicht mehr brauchst. – Rotem

+0

Ähnlichkeiten: http://stackoverflow.com/questions/4318563/c-sharp-out-of-memory-when-creating-bitmap –

+1

Verfügen Sie über die Bitmap selbst, nachdem Sie damit fertig sind? –

Antwort

1

Sie müssen die verfügbaren Ressourcen entsorgen, sobald Sie mit ihnen fertig sind. Bitmap Klasse implementiert IDisposable - so ist es Einweg-Ressource. Richtige Muster statt

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

So etwas wie

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

oder in Kurzform (was bevorzugt ist):

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

Referenz: Using Objects That Implement IDisposable

bearbeiten

Sie können das Problem leicht emulieren:

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

Wenn 'Bitmap' das IDisposable korrekt implementiert, sollte es sich dann nicht selbstständig machen, wenn keine Referenzen mehr vorhanden sind? Zumindest würde es, wenn es der Destruktor-Logik folgt, die hier beschrieben wird: http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface –

+0

@Thomas - hast du die angenommene Antwort gelesen? :) Der Garbage Collector befreit JUST-gemanagte Ressourcen - wenn Sie also auf nicht verwalteten Speicher (und Bitmap-Klasse) verweisen, bleibt der zugeordnete nicht verwaltete Speicher bis zum Ende des Prozesses reserviert. –

+0

Nein, schauen Sie sich 'protected void Dispose (Boolean itIsSafeToAlsoFreeManagedObjects)' an: es gibt immer unmanaged Ressourcen frei. –