2009-08-26 5 views
1

Heute bin ich auf ein Dilemma gestoßen. Ich habe eine App erstellt, die GDI + verwendet, um auf ein Formular zu zeichnen. Die Zeichnung wird jede Sekunde von einem Timer ausgelöst. Die draw-Methode verwendet eine for-Schleife, um eine Sammlung von Objekten zu durchlaufen, und wenn sie einen bestimmten Status haben, zeichnen Sie sie.C# GDI +, Erstellen eines LinearGradientBrush in einer Schleife (Speicherlecks)

Ich möchte sie mit einem LinearGradientBrush zeichnen, einfach weil es so viel schöner aussieht als ein einfacher Pinsel. Werfen Sie einen Blick auf die folgende

  //minutes 
     foreach (Led l in MinuteGrid.Leds) 
     { 
      LinearGradientBrush b = new LinearGradientBrush 
       (l.LedRectangle, Color.GreenYellow, Color.Green, 110); 

      if (l.IsLit) 
       g.FillRectangle(b, l.LedRectangle); 

      b.Dispose(); 
     } 

Ich bin ein neuer LinearGradientBrush für jede Iteration der Schleife zu schaffen (was mich stört), aber das ist, weil ich zu haben. Ich kann keinen außerhalb der Schleife erstellen, da sein Konstruktorsatz verlangt, dass ich Parameter setze, die nur innerhalb der Schleife bekannt sind.

Ich finde, dass die Verwendung der dispose-Methode für das LinearGradientBrush-Objekt nicht so zuverlässig ist. Wenn ich meine App starte und sie im Task-Manager anschaue, spuckt sie ihren Speicher aus. Als ich dann fügen Sie die b = null Linie, die enorm zu helfen scheint, als

  foreach (Led l in MinuteGrid.Leds) 
     { 
      LinearGradientBrush b = new LinearGradientBrush 
       (l.LedRectangle, Color.GreenYellow, Color.Green, 110); 

      if (l.IsLit) 
       g.FillRectangle(b, l.LedRectangle); 

      if (b != null) 
      { 
       b.Dispose(); 
       b = null; 
      } 
     } 

folgt bin ich frage mich nur, wenn es eine bessere Art und Weise mit LinearGradientBrushes zu arbeiten? Oder gibt es eine bessere Lösung?

Vielen Dank

Antwort

0

Fügen Sie jedem LED eine Farbverlaufsbürste hinzu. Wenn Sie es nicht zu dieser Klasse hinzufügen können, können Sie ein Dictionary < Led, GradientBrush > verwenden, um die Pinsel zu speichern, um einfachen Zugriff darauf zu erhalten. diese Weise können Sie nur eine Bürste benötigen pro LED statt einer pro Schleifeniterationslatenzzeit,

(auch in Ihrem Beispiel-Code, gibt es keinen Punkt die Bürste, wenn! L.IsLit erstellen)

+0

Ohrfeigen, doh! natürlich sind Sie so richtig, ich bin ein bisschen peinlich davon :) –

6

ich empfehlen würde mit eine "using" Anweisung:

foreach (Led l in MinuteGrid.Leds) 
{ 
    if (l.IsLit) 
    { 
     using(LinearGradientBrush b = new LinearGradientBrush(l.LedRectangle, Color.GreenYellow, Color.Green, 110)) 
     { 
      g.FillRectangle(b, l.LedRectangle); 
     } 
    } 
} 

jedoch nicht vergessen, Dispose() nicht frei (verwaltet) Speicher. Es gibt nur die nicht verwalteten Ressourcen frei (was wichtig ist und möglicherweise nicht verwalteten Speicher enthält). Der Speicher wird nicht freigegeben, bis der GC ausgeführt wird, was während der Schleife nicht passieren kann.

Wenn jedoch der Speicherdruck zu hoch wird, sollte der Garbage Collector innerhalb Ihrer Schleife ausgeführt werden, und Sie werden sehen, dass er fällt. So ist .NET konzipiert - nehmen Sie es einfach an und machen Sie sich keine Sorgen. Der GC wird schließlich diese Erinnerung sammeln, also ist es nicht etwas, worüber man sich Sorgen machen muss.

+0

Bingo ... um Ihre Theorie zu testen, sollten sie gc.collect am Ende jeder Ausführung aufrufen und sehen, ob der Speicher erneut beansprucht wird ... Stichwort In diesem ist "test", lass gc.collects nicht im Produktionscode stehen. –

0

Dispose hat nichts damit zu tun, verwalteten Speicher freizugeben. Das wird komplett von GC erledigt, die "wenn nötig" läuft. Da der Pinsel jedoch höchstwahrscheinlich einen Griff hält, sollten Sie ihn entsorgen. Ich würde empfehlen, dass Sie das in einem using Block tun, anstatt manuell Dispose aufzurufen, da dies sicherstellt, dass Dispose sogar in Anwesenheit einer Ausnahme aufgerufen wird.

0

Wenn die Anzahl der Permutationen ist begrenzt Sie können nur vorab erstellen, um alle Ihre Pinsel einmal:

LinearGradientBrush rectGreenBrush = new LinearGradientBrush(l.LedRect........); 
LinearGradientBrush rectRedBrush = new LinearGradientBrush(l.LedRect........); 

foreach (Led l in MinuteGrid.Leds) 
{ 
    LinearGradientBrush b = null; 
    if (xxx) 
    b = rectGreenBrush; 
    else if (yyyy) 
    b = rectRedBrush; 
    else..... 


    do painting 
} 

cleanup brushes 

Eine zweite Option ist ähnlich, aber die Bürsten nach Bedarf zu erzeugen; Die anderen Antworten sind korrekt, dass .NET die Verwendung von verwaltetem Speicher zulassen kann, solange es nichts schädigt.

Dies sollte jedoch dazu beitragen, das Erstellen/Löschen weitgehend zu vermeiden, wenn viele Led-Objekte durchlaufen werden müssen.

+0

Clyde, vielen Dank, aber ich verweise Sie auf mt Original Post. 1. Ich kann die Pinsel nicht außerhalb der Schleife erstellen, da Parameter, die für ihre Erstellung benötigt werden (LED-Rechteck) nur innerhalb der Schleife bekannt sind. 2. Was ist das Objekt "FindOrCreateBrushBasedOnLed" in Ihrem Code? woher kommt das? Vielen Dank –