2009-04-28 1 views
40

Viele Typen in WPF stammen von Freezable. Es bietet veränderbaren POCO-Objekten Unveränderbarkeit und ermöglicht offensichtlich eine verbesserte Leistung in bestimmten Situationen.In welchen Szenarien profitieren einfrierende WPF-Objekte stark von der Leistung?

Hat jemand gefunden, dass das Einfrieren von Objekten in ihrer WPF-Anwendung die Leistung stark verbessert hat? Wenn ja, welche Artikel haben dann beim Tiefgefrieren den größten Leistungsunterschied?

(Beachten Sie, dass ich geschrieben habe ein similar but different question auch)

Antwort

43

Sie könnten in meine Erfahrungen mit Freezable interessieren:

ich einmal ein PDF-Viewer MuPDF schrieb die Bitmaps macht, dass ich Rendern mit WPF. Was die Leistung erheblich verbessert, ist, dass ich die Seiten-Bitmaps in einem Hintergrund-Thread rendern, einfrieren und dann an den UI-Thread übergeben kann. Es ist schön, dass WPF das Bild nicht kopiert, um es einzufrieren, aber die Fähigkeit, all diese Vorbereitungen in einem Hintergrundthread durchzuführen, war der Hauptvorteil für mich.

Von dem, was ich verstehe, müssen alle Visuals eingefroren werden, damit sie von dem WPF-Render-Thread sicher gerendert werden können. Wenn Sie große ungefrotete Visualisierungen rendern, werden sie in gefrorene Grafiken geklont, wenn sie von WPF gerendert werden. Wenn Sie Ihre statischen Bitmaps vorher einfrieren, kann WPF den Zeiger nur mit dem Render-Thread teilen, ohne zu klonen. Nicht eingefrorene Objekte können sogar wiederholt kopiert werden, wenn WPF nicht weiß, ob das Objekt seit der letzten Wiedergabe geändert wurde. Gefrorene Objekte machen das Kopieren überflüssig.

+0

Sehr hilfreich danke. Ich wusste nicht, dass du das auf einem Hintergrundthread tun könntest, sollte einer meiner Apps erheblich helfen! – Kelly

16

Diese potenziellen Speicherlecks passieren könnte, wenn Sie die Bildsteuerung verwenden (und nicht Freeze-Methode):

a) Sie verwenden Bitmap als Bild Quelle und nicht loslassen Bitmap:

static BitmapImage bi1 = new BitmapImage(new Uri("Bitmap1.bmp",UriKind.RelativeOrAbsolute)); 
m_Image1 = new Image(); 
m_Image1.Source = bi1; 
//bi1.Freeze() 
//if you do not Freeze, your app will leak memory. 
MyStackPanel.Children.Add(m_Image1); 

b) Sie weisen mehrere Bitmap als Bildquelle und lassen Sie nicht alle der Bitmap Sie verwendet (ähnlich (a)). Dieser führte in .Net 3.5:

static BitmapImage bi1 = new BitmapImage(new Uri("Bitmap1.bmp", 
UriKind.RelativeOrAbsolute)); 
static BitmapImage bi2 = new BitmapImage(new Uri("Bitmap2.bmp", 
UriKind.RelativeOrAbsolute)); 
bi2.Freeze(); 
m_Image1 = new Image(); 
//bi1.Freeze() 
//even though you are really using bi2 for Image Source, 
//you also need to Freeze bi1 it to avoid leak 
m_Image1.Source = bi1; // use un-frozen bitmap, which causes the leak 
m_Image1.Source = bi2; // use frozen bitmap 
MyStackPanel.Children.Add(m_Image1); 

Quelle: WPF Performance

+0

Ich nehme an, Sie beziehen sich auf die hier beschriebenen Szenarien: https://blogs.msdn.microsoft.com/jgoldb/2008/02/04/finding-memory-leaks-in-wpf-based-applications/ (Sie sollte den spezifischen Link in Ihre Antwort einfügen). Ich denke, es lohnt sich, darauf hinzuweisen, dass das Einfrieren der Bitmap in diesen Szenarien nur eine Ausweichmöglichkeit für etwas darstellt, das grundsätzlich als eine schlechte Idee betrachtet werden könnte, dh ein "statisches" Feld zum Speichern einer Bitmap zu verwenden referenziert in einem Image-Objekt. –

+0

Das 'Image'-Objekt muss notwendigerweise Änderungsereignisse abonnieren, daher behält die Bitmap eine starke Referenz bei, die verhindert, dass der GC des' Image' und natürlich alles, was _its_ subscribe, Ereignisse ändert. Dies ist wirklich ein breiteres Problem, das Menschen, die ereignisgesteuerten Code schreiben, beachten müssen: Ein 'statisches' Feld kann eine ganze Baumstruktur von Objekten rooten, wenn diese Objekte indirekt von Ereignisfeldern referenziert werden. Einfrieren einer Bitmap ist aus anderen Gründen gut, aber eine bessere Lösung für das Leck besteht darin, ein Bitmap-Objekt in einem statischen Feld nicht zu behalten, wenn Sie es nicht mehr benötigen (z. B. wenn das Fenster geschlossen ist). –

12

Obwohl Sie die Antwort bereits akzeptiert haben, wollte nur eine andere Version der Antwort protokollieren, die mir besser geholfen hat.

Von MSDN (minor edit):

Wenn Sie die Kontrolle halten Verweis auf nicht verwalteten Low-Level-Ressourcen ändern waren (zB: Pinsel), würde jede Änderung hat diese Low-Level-Objekte zu regenerieren!

Die Freezable-Klasse gibt einem Pinsel die Möglichkeit seine entsprechenden generierten Low-Level-Objekte zu finden und sie zu aktualisieren, wenn er sich ändert. Wenn diese Fähigkeit aktiviert ist, wird der Pinsel als "ungefroren" angezeigt.

Die freeze-Methode von freezable ermöglicht es Ihnen, diese selbstaktualisierende -Fähigkeit zu deaktivieren. Sie können diese Methode verwenden, um den Pinsel "eingefroren" zu machen, oder nicht änderbar. So, die Leistung zu verbessern.

Und der Code die Nutzung zu erklären:

  Button myButton = new Button(); 
      SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow); 

      if (myBrush.CanFreeze) 
      { 
       // Makes the brush unmodifiable. 
       myBrush.Freeze(); 
      }     
      myButton.Background = myBrush;   
      if (myBrush.IsFrozen) // Evaluates to true. 
      { 
       // If the brush is frozen, create a clone and modify the clone. 
       SolidColorBrush myBrushClone = myBrush.Clone(); 
       myBrushClone.Color = Colors.Red; 
       myButton.Background = myBrushClone; 
      } 
      else 
      { 
       // If the brush is not frozen, it can be modified directly. 
       myBrush.Color = Colors.Red; 
      } 
+0

Ich weiß, das ist ein alter Beitrag, aber ein Link zum MSDN-Artikel wäre nett. – PeterM

+0

Aktualisiert. Vielen Dank. –

2

ich eine leistungsstarke Bildbetrachter-Anwendung entwickelt. Wir hatten Code auf dem Back-End, das eine neue Bitmap jeden Frame erstellt und schrieb, dass Bitmap auf dem Bildschirm wie folgt:

Writeablebitmap wb = new WriteableBitmap(); 
// < code to set the wb pixel values here > 

// Push the bitmap to the screen 
image.Source = wb; 

Während des Tests haben wir festgestellt, dass es eine schreckliche Flackern war beim Gehen mehr als 30 FPS mit mäßig -große Bilder (1080p). Die Reparatur? Frieren Sie das Bitmap ein, bevor Sie es auf die image.Quelle setzen. Kein Produkt-Tötungsleistungsfehler mehr. Heutzutage versuche ich alles einzufrieren, was ich kann.

Verwandte Themen