Ottimizzazione delle prestazioni: comportamento degli oggetti

Aggiornamento: novembre 2007

La comprensione del comportamento intrinseco degli oggetti WPF facilita l'individuazione del compromesso ideale tra funzionalità e prestazioni.

Nel presente argomento sono contenute le seguenti sezioni.

  • La mancata rimozione dei gestori eventi dagli oggetti può mantenere gli oggetti attivi
  • Proprietà e oggetti di dipendenza
  • Oggetti Freezable
  • Virtualizzazione dell'interfaccia utente
  • Argomenti correlati

La mancata rimozione dei gestori eventi dagli oggetti può mantenere gli oggetti attivi

Il delegato passato da un oggeto al relativo evento è un riferimento effettivo a tale oggetto. Di conseguenza, i gestori eventi possono mantenere gli oggetti attivi più a lungo del previsto. Quando si esegue la pulitura di un oggetto registrato per restare in ascolto di un evento dell'oggetto, è essenziale rimuovere tale delegato prima di rilasciare l'oggetto. Mantenere attivi oggetti non necessari aumenta l'utilizzo di memoria dell'applicazione. Questa situazione si verifica soprattutto quando l'oggetto è la radice di un albero logico o di una struttura ad albero visuale.

In WPF viene introdotto un modello di listener di eventi debole per eventi che possono rivelarsi utili in situazioni in cui è difficile tenere traccia delle relazioni di durata degli oggetti tra origine e listener. Alcuni eventi WPF esistenti utilizzano questo modello. Questo modello può essere utile per implementare oggetti con eventi personalizzati. Per informazioni dettagliate, vedere Modelli WeakEvent.

Sono disponibili vari strumenti, ad esempio il profiler CLR Profiler e il visualizzatore del working set, in grado di fornire informazioni sull'utilizzo della memoria di un determinato processo. Il profiler CLR include numerose visualizzazioni del profilo di allocazione utili, tra cui un istogramma dei tipi allocati, grafici delle allocazioni e delle chiamate, una cronologia che mostra le operazioni di Garbage Collection di varie generazioni e lo stato dell'heap gestito che ne deriva e una struttura ad albero delle chiamate che mostra le allocazioni per metodo e i caricamenti degli assembly. Per ulteriori informazioni, visitare il sito .NET Framework Developer Center (informazioni in lingua inglese).

Il visualizzatore del working set è uno strumento di analisi delle prestazioni di WPF che fornisce informazioni sull'utilizzo della memoria di un determinato processo. Questo strumento consente di generare uno snapshot delle informazioni sull'utilizzo della memoria dell'applicazione in un determinato stato dell'applicazione. Per ulteriori informazioni sugli strumenti di prestazioni di WPF, vedere Strumenti di analisi delle prestazioni per WPF.

Proprietà e oggetti di dipendenza

In genere, l'accesso a una proprietà di dipendeza di un oggetto DependencyObject non è più lento dell'accesso a una proprietà CLR. Sebbene vi sia un leggero sovraccarico delle prestazioni per l'impostazione del valore di una proprietà, ottenere un valore è rapido quanto ottenere il valore da una proprietà CLR. Il sovraccarico delle prestazioni è tuttavia compensato dal fatto che le proprietà di dipendenza supportano funzionalità efficienti, quali l'associazione ai dati, l'animazione, l'ereditarietà e l'applicazione di stili. Per ulteriori informazioni, vedere Cenni preliminari sulle proprietà di dipendenza.

Ottimizzazioni di DependencyProperty

È necessario definire con grande attenzione le proprietà di dipendenza nell'applicazione. Se un oggetto DependencyProperty influisce solo su opzioni di metadati di tipo rendering, anziché su altre opzioni di metadati come AffectsMeasure, è necessario contrassegnarlo come tale eseguendo l'override dei metadati. Per ulteriori informazioni sull'override o su come ottenere i metadati delle proprietà, vedere Metadati della proprietà di dipendenza.

Nel caso in cui non tutte le modifiche delle proprietà influiscono effettivamente sulla misura, la disposizione e il rendering, può essere più efficace disporre di un gestore delle modifiche delle proprietà che invalidi la misura, la disposizione e i passaggi di rendering manualmente. Ad esempio, è possibile decidere di eseguire nuovamente il rendering di uno sfondo solo quando un valore è superiore a un limite impostato. In questo caso, il rendering verrebbe invalidato dal gestore delle modifiche delle proprietà solo quando il valore supera il limite impostato.

Problemi legati alla possibilità di rendere ereditabile un oggetto DependencyProperty

Per impostazione predefinita, le proprietà di dipendenza registrate non sono ereditabili. Tuttavia, è possibile rendere ereditabile qualsiasi proprietà in modo esplicito. Sebbene si tratti di una funzionalità utile, la conversione di una proprietà per renderla ereditabile ha un impatto sulle prestazioni poiché aumenta la durata dell'annullamento della convalida della proprietà.

Utilizzo di RegisterClassHandler

Mentre la chiamata a RegisterClassHandler consente di salvare lo stato dell'istanza, è importante sapere che il gestore viene chiamato per tutte le istanze, con conseguenti problemi di prestazioni. Utilizzare RegisterClassHandler solo quando l'applicazione richiede il salvataggio dello stato dell'istanza.

Impostazione del valore predefinito di un oggetto DependencyProperty durante le registrazione

Quando si crea un oggetto DependencyProperty che richiede un valore predefinito, impostare il valore utilizzando i metadati predefiniti passati come parametro al metodo Register di DependencyProperty. Utilizzare questa tecnica anziché l'impostazione del valore della proprietà in un costruttore o su ciascuna istanza di un elemento.

Impostazione del valore di PropertyMetadata utilizzando Register

Quando si crea un oggetto DependencyProperty, è possibile impostare PropertyMetadata utilizzando i metodi Register o OverrideMetadata. Sebbene l'oggetto possa disporre di un costruttore statico per chiamare OverrideMetadata, non si tratta della soluzione ottimale a causa dell'impatto sulle prestazioni. Per garantire prestazioni ottimali, impostare PropertyMetadata durante la chiamata a Register.

Oggetti Freezable

Freezable è un tipo di oggetto speciale che presenta due stati: non bloccato e bloccato. Bloccare gli oggetti ogni volta che è possibile migliora le prestazioni dell'applicazione e ne riduce il working set. Per ulteriori informazioni, vedere Cenni preliminari sugli oggetti Freezable.

Ogni oggetto Freezable presenta un evento Changed che viene generato a ogni modifica dell'oggetto. Tuttavia, le notifiche delle modifiche sono dispendiose in termini di prestazioni dell'applicazione.

Nell'esempio riportato di seguito ogni Rectangle utilizza lo stesso oggetto Brush:

rectangle_1.Fill = myBrush;
rectangle_2.Fill = myBrush;
rectangle_3.Fill = myBrush;
// ...
rectangle_10.Fill = myBrush;

Per impostazione predefinita, WPF fornisce un gestore eventi per l'evento Changed dell'oggetto SolidColorBrush per invalidare la proprietà Fill dell'oggetto Rectangle. In questo caso, ogni volta che l'evento Changed deve essere generato da SolidColorBrush, è necessario richiamare la funzione di callback per ogni Rectangle. L'accumulo di queste chiamate alla funzione di callback causa una riduzione significativa delle prestazioni. Inoltre, aggiungere e rimuovere i gestori a questo punto è molto dispendioso in termini di prestazioni poiché per eseguire tali operazioni l'applicazione deve scorrere tutto l'elenco. Se lo scenario dell'applicazione non modifica mai l'oggetto SolidColorBrush, sulle prestazioni influirà il fatto di conservare gestori per eventi Changed non necessari.

Il blocco di un oggetto Freezable consente di migliorarne le prestazioni poiché evita di dover impiegare risorse nella conservazione delle notifiche delle modifiche. Nella tabella riportata di seguito vengono illustrate le dimensioni di un semplice oggetto SolidColorBrush quando la relativa proprietà IsFrozen è impostata su true, rispetto a quando non lo è. Si presuppone l'applicazione di un pennello alla proprietà Fill di dieci Rectangle.

Stato

Dimensioni

Oggetto SolidColorBrush bloccato

212 byte

Oggetto SolidColorBrush non bloccato

972 byte

Nell'esempio di codice riportato di seguito viene illustrato questo concetto:

Brush frozenBrush = new SolidColorBrush(Colors.Blue);
frozenBrush.Freeze();
Brush nonFrozenBrush = new SolidColorBrush(Colors.Blue);

for (int i = 0; i < 10; i++)
{
    // Create a Rectangle using a non-frozed Brush.
    Rectangle rectangleNonFrozen = new Rectangle();
    rectangleNonFrozen.Fill = nonFrozenBrush;

    // Create a Rectangle using a frozed Brush.
    Rectangle rectangleFrozen = new Rectangle();
    rectangleFrozen.Fill = frozenBrush;
}

I gestori modificati su oggetti Freezable non bloccati può mantenere gli oggetti attivi

Il delegato passato da un oggetto all'evento Changed di un oggetto Freezable è un riferimento effettivo a tale oggetto. Di conseguenza, i gestori di eventi Changed possono mantenere gli oggetti attivi più a lungo del previsto. Quando si esegue la pulitura di un oggetto registrato per restare in ascolto di un evento Changed dell'oggetto Freezable, è essenziale rimuovere tale delegato prima di rilasciare l'oggetto.

WPF esegue anche l'associazione di eventi Changed internamente. Ad esempio, tutte le proprietà di dipendenza che accettano Freezable come valore rimangono automaticamente in ascolto di eventi Changed. Questo concetto viene illustrato dalla proprietà Fill, che accetta Brush.

Brush myBrush = new SolidColorBrush(Colors.Red);
Rectangle myRectangle = new Rectangle();
myRectangle.Fill = myBrush;

Al momento dell'assegnazione di myBrush a myRectangle.Fill, un delegato che punta all'oggetto Rectangle viene aggiunto all'evento Changed dell'oggetto SolidColorBrush. Nel codice riportato di seguito, pertanto, myRect non viene effettivamente reso idoneo per Garbage Collection:

myRectangle = null;

In questo caso myBrush mantiene myRectangle attivo e lo richiama al momento della generazione del relativo evento Changed. Si noti che l'assegnazione di myBrush alla proprietà Fill di un nuovo oggetto Rectangle aggiunge semplicemente un altro gestore eventi a myBrush.

Per eseguire la pulitura di questi tipi di oggetti è consigliabile rimuovere Brush dalla proprietà Fill, che a sua volta rimuove il gestore di eventi Changed.

myRectangle.Fill = null;
myRectangle = null;

Virtualizzazione dell'interfaccia utente

In WPF è disponibile anche una variante dell'elemento StackPanel che consente di virtualizzare automaticamente il contenuto figlio con associazione a dati. In questo contesto, il termine virtualizzare fa riferimento a una tecnica tramite cui viene generato un sottoinsieme di UIElements, a partire da un numero più elevato di elementi di dati in base agli elementi visibili sullo schermo. Generare un numero elevato di elementi dell'interfaccia utente, di cui solo alcuni vengono visualizzati sullo schermo in un determinato momento, richiede un consumo intenso di risorse in termini di memoria e processore. Con VirtualizingStackPanel, tramite la funzionalità fornita da VirtualizingPanel, vengono calcolati gli elementi visibili e viene utilizzato ItemContainerGenerator di ItemsControl (ad esempio ListBox o ListView) per creare UIElements solo per gli elementi visibili.

Per ottimizzare le prestazioni, gli oggetti visivi per questi elementi vengono generati o mantenuti attivi solo se sono visibili sullo schermo. Quando non si trovano più nell'area visualizzabile del controllo, è possibile rimuovere gli oggetti visibili. Questa operazione non deve essere confusa con la virtualizzazione dei dati, in cui gli oggetti dati non sono tutti presenti nell'insieme locale, ma inviati nel flusso in base alle esigenze.

Nella tabella riportata di seguito viene indicato il tempo trascorso per l'aggiunta e il rendering di 5000 elementi TextBlock in un oggetto StackPanel e in un oggetto VirtualizingStackPanel. In questo scenario, le misure rappresentano il tempo compreso tra il collegamento di una stringa di testo alla proprietà ItemsSource di un oggetto ItemsControl e il tempo in cui tale stringa di testo viene visualizzata nel riquadro.

Riquadro host

Durata del rendering (ms)

StackPanel

3210

VirtualizingStackPanel

46

Vedere anche

Concetti

Ottimizzazione delle prestazioni di applicazioni WPF

Pianificazione delle prestazioni dell'applicazione

Ottimizzazione delle prestazioni: sfruttare appieno l'hardware

Ottimizzazione delle prestazioni: layout e progettazione

Ottimizzazione delle prestazioni: grafica bidimensionale e creazione di immagini

Ottimizzazione delle prestazioni: risorse di applicazioni

Ottimizzazione delle prestazioni: testo

Ottimizzazione delle prestazioni: associazione dati

Ottimizzazione delle prestazioni: altri suggerimenti

Strumenti e risorse relativi alle prestazioni WPF