2009-04-28 6 views
40

De nombreux types dans WPF dérivent de Freezable. Il fournit l'immuabilité aux objets POCO mutables et, apparemment, permet d'améliorer les performances dans certaines situations.Dans quels scénarios les objets WPF gelés bénéficient-ils grandement des performances?

Est-ce que quelqu'un a trouvé que le gel des objets dans leur application WPF a grandement amélioré les performances? Si oui, alors quels articles ont donné la plus grande différence de performance lorsqu'ils sont gelés?

(Notez que j'ai posté un similar but different question aussi)

Répondre

43

Vous pourriez être intéressé par mes expériences avec Freezable:

J'ai écrit une visionneuse de PDF à l'aide mupdf qui rend bitmaps, que je rendre avec WPF. Ce qui aide grandement les performances, c'est que je peux restituer les bitmaps de la page sur un thread d'arrière-plan, les geler, puis les transmettre au thread de l'interface utilisateur. C'est bien que WPF ne copie pas l'image pour la geler, mais la possibilité de faire toute cette préparation sur un thread d'arrière-plan a été le principal avantage pour moi. D'après ce que je comprends, tous les visuels doivent être gelés afin qu'ils puissent être rendus en toute sécurité par le thread de rendu WPF. Si vous affichez de grands visuels non gelés, ils seront clonés à ceux qui sont figés lorsque WPF les rendra. Si vous geler au préalable vos bitmaps statiques, WPF peut simplement partager le pointeur avec le thread de rendu sans le cloner. Les objets non gelés peuvent même être copiés plusieurs fois si WPF ne sait pas si l'objet a été modifié depuis la dernière fois qu'il a été rendu. Les objets gelés éliminent le besoin de toute cette copie.

+0

Très utile merci. Je ne savais pas que vous pourriez faire cela sur un fil de fond, devrait considérablement aider une de mes applications! – Kelly

16

Ces éventuelles fuites de mémoire pourraient se produire si vous utilisez le contrôle de l'image (et ne pas utiliser la méthode Freeze):

a) Vous utilisez BitmapImage que l'image source et ne relâchez pas le BitmapImage:

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) vous affecter plusieurs BitmapImage comme source d'image et ne libèrent pas tous les BitmapImage que vous avez utilisé (similaire à (a)). Celui-ci introduit en .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); 

Source: WPF Performance

+0

Je suppose que vous faites référence aux scénarios décrits ici: https://blogs.msdn.microsoft.com/jgoldb/2008/02/04/finding-memory-leaks-in-wpf-based-applications/ (vous devrait mettre le lien spécifique dans votre réponse). Je pense qu'il vaut la peine de souligner que geler le bitmap dans ces scénarios est juste une solution pour ce qui pourrait fondamentalement être considéré comme une mauvaise idée en premier lieu, à savoir en utilisant un champ statique pour stocker un bitmap que vous avez ensuite référencé dans un objet 'Image'. –

+0

L'objet 'Image' doit nécessairement s'abonner pour changer les événements, ainsi le bitmap conserve une référence forte, empêchant GC de' Image', et bien sûr de tout ce qui souscrit à _its_ change les évènements. C'est vraiment un problème plus large que les gens qui écrivent un code axé sur les événements doivent être conscients de: un champ 'static' peut enraciner un arbre entier d'objets, si ces objets sont indirectement référencés par des champs d'événement. Le gel d'un bitmap est bon pour d'autres raisons, mais une meilleure solution à la fuite consiste à ne pas conserver un objet bitmap dans un champ statique lorsque vous n'en avez plus besoin (par exemple lorsque la fenêtre est fermée). –

12

Bien que vous avez déjà accepté la réponse, je voulais juste enregistrer une version différente de la réponse qui m'a aidé à mieux.

De MSDN (modification mineure):

Si vous deviez modifier le contrôle tenant référence aux ressources à faible niveau non gérés (par exemple: brosse), chaque modification aurait à régénérer ces objets bas niveau!

La classe freezable permet à un pinceau de trouver les objets de bas niveau générés correspondants et de les mettre à jour lorsqu'il change. Lorsque cette capacité est activée, la brosse est dite pour être "dégelée".

La méthode Freeze d'un freezable vous permet de désactiver cette capacité de mise à jour automatique . Vous pouvez utiliser cette méthode pour rendre le pinceau "gelé" ou non modifiable. Ainsi, améliorer les performances.

Et, le code pour expliquer l'utilisation:

  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

Je sais que c'est un vieux message, mais un lien vers l'article MSDN serait bien. – PeterM

+0

Mis à jour. Merci. –

2

j'ai développé une application de visualisation d'images haute performance. Nous avions code sur le back-end qui a créé une nouvelle image chaque image et écrit que bitmap à l'écran comme ceci:

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

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

Au cours des essais, nous avons remarqué qu'il y avait une terrible vacillante en allant de 30 FPS modérément images-taille (1080p). Le correctif? Juste geler le bitmap avant de le mettre à l'image.Source. Plus de bug de performance qui tue le produit. De nos jours, j'essaie de geler tout ce que je peux.

Questions connexes