パフォーマンスの最適化 : オブジェクトの動作Optimizing Performance: Object Behavior

WPFWPF オブジェクトに固有の動作を理解することは、機能とパフォーマンスのバランスを見極めるうえで役に立ちます。Understanding the intrinsic behavior of WPFWPF objects will help you make the right tradeoffs between functionality and performance.

オブジェクトのイベント ハンドラーを削除しないとオブジェクトが維持される可能性があるNot Removing Event Handlers on Objects may Keep Objects Alive

オブジェクトがそのイベントに渡すデリゲートは、事実上そのオブジェクトへの参照です。The delegate that an object passes to its event is effectively a reference to that object. このため、イベント ハンドラーによってオブジェクトが本来より長く維持される可能性があります。Therefore, event handlers can keep objects alive longer than expected. オブジェクトのイベントをリッスンするように登録されているオブジェクトのクリーンアップを実行するときには、オブジェクトを解放する前にそのデリゲートを削除することが重要です。When performing clean up of an object that has registered to listen to an object's event, it is essential to remove that delegate before releasing the object. 不要なオブジェクトが残っていると、アプリケーションのメモリ使用量が増加します。Keeping unneeded objects alive increases the application's memory usage. これは、オブジェクトが論理ツリーやビジュアル ツリーのルートである場合には特に重要になります。This is especially true when the object is the root of a logical tree or a visual tree.

WPFWPF によって導入される弱いイベント リスナー パターンは、ソースとリスナーのオブジェクト有効期間の関係の追跡が困難な場合に役に立ちます。introduces a weak event listener pattern for events that can be useful in situations where the object lifetime relationships between source and listener are difficult to keep track of. 一部の既存の WPFWPF イベントはこのパターンを使用します。Some existing WPFWPF events use this pattern. カスタム イベントを持つオブジェクトを実装する場合に、このパターンが役に立つこともあります。If you are implementing objects with custom events, this pattern may be of use to you. 詳細については、「弱いイベント パターン」を参照してください。For details, see Weak Event Patterns.

CLR プロファイラーや作業セット ビューアーなど、特定のプロセスのメモリ使用量に関する情報を入手できるツールもいくつかあります。There are several tools, such as the CLR Profiler and the Working Set Viewer, that can provides information on the memory usage of a specified process. CLR プロファイラーには、割り当てられた型のヒストグラム、割り当てグラフと呼び出しグラフ、さまざまなジェネレーションのガベージ コレクションとその結果のマネージド ヒープの状態を示す時系列、メソッドごとの割り当てとアセンブリの読み込みを示す呼び出しツリーなど、非常に便利な割り当てプロファイルのビューがいくつか含まれています。The CLR Profiler includes a number of very useful views of the allocation profile, including a histogram of allocated types, allocation and call graphs, a time line showing garbage collections of various generations and the resulting state of the managed heap after those collections, and a call tree showing per-method allocations and assembly loads. 詳しくは、「パフォーマンス」をご覧ください。For more information, see Performance.

依存関係プロパティと依存関係オブジェクトDependency Properties and Objects

一般に、aDependencyObjectの依存関係プロパティへのアクセスは、CLR プロパティへのアクセスよりも遅くはありません。In general, accessing a dependency property of a DependencyObject is not slower than accessing a CLR property. プロパティ値を設定する場合のパフォーマンスのオーバーヘッドは少ないですが、値を取得する速度は、CLR プロパティから値を取得するのと同じくらい速いです。While there is a small performance overhead for setting a property value, getting a value is as fast as getting the value from a CLR property. この小さなパフォーマンス オーバーヘッドがある代わりに、依存関係プロパティでは、データ バインディング、アニメーション、継承、スタイル設定などの堅牢な機能がサポートされています。Offsetting the small performance overhead is the fact that dependency properties support robust features, such as data binding, animation, inheritance, and styling. 依存関係プロパティの詳細については、「依存関係プロパティの概要」を参照してください。For more information, see Dependency Properties Overview.

DependencyProperty の最適化DependencyProperty Optimizations

アプリケーションで依存関係プロパティを定義するときには注意が必要です。You should define dependency properties in your application very carefully. などの他DependencyPropertyのメタデータ オプションではなく、レンダー タイプのメタデータ オプションAffectsMeasureにのみ影響する場合は、メタデータをオーバーライドしてそのようにマークする必要があります。If your DependencyProperty affects only render type metadata options, rather than other metadata options such as AffectsMeasure, you should mark it as such by overriding its metadata. プロパティ メタデータをオーバーライドまたは取得する方法の詳細については、「依存関係プロパティのメタデータ」を参照してください。For more information about overriding or obtaining property metadata, see Dependency Property Metadata.

すべてのプロパティ変更が実際に測定、配置、描画に影響するわけではない場合は、測定、配置、描画の各パスを、プロパティ変更ハンドラーによって手動で無効にした方が効率的な場合もあります。It may be more efficient to have a property change handler invalidate the measure, arrange, and render passes manually if not all property changes actually affect measure, arrange, and render. たとえば、設定した制限値より値が大きい場合にのみ背景を再描画する場合は、For instance, you might decide to re-render a background only when a value is greater than a set limit. 設定した制限値を値が超えていた場合にのみプロパティ変更ハンドラーで描画を無効にします。In this case, your property change handler would only invalidate render when the value exceeds the set limit.

DependencyProperty を継承可能にするとパフォーマンスへの負荷が発生するMaking a DependencyProperty Inheritable is Not Free

既定では、登録した依存関係プロパティは継承不可になります。By default, registered dependency properties are non-inheritable. ただし、プロパティはどれでも明示的に継承可能にすることができます。However, you can explicitly make any property inheritable. この機能は便利ですが、プロパティを継承可能にすると、プロパティの無効化の時間が増加して、パフォーマンスに影響します。While this is a useful feature, converting a property to be inheritable impacts performance by increasing the length of time for property invalidation.

RegisterClassHandler は慎重に使用するUse RegisterClassHandler Carefully

呼びRegisterClassHandler出しによってインスタンスの状態を保存できますが、すべてのインスタンスでハンドラが呼び出され、パフォーマンスの問題が発生する可能性があることに注意してください。While calling RegisterClassHandler allows you to save your instance state, it is important to be aware that the handler is called on every instance, which can cause performance problems. アプリケーションでRegisterClassHandlerインスタンスの状態を保存する必要がある場合にのみ使用します。Only use RegisterClassHandler when your application requires that you save your instance state.

DependencyProperty の既定値は登録時に設定するSet the Default Value for a DependencyProperty during Registration

既定値を必要DependencyPropertyとする を作成する場合は、 のメソッドにパラメーターとして渡される既定のRegisterメタデータを使用して値DependencyPropertyを設定します。When creating a DependencyProperty that requires a default value, set the value using the default metadata passed as a parameter to the Register method of the DependencyProperty. コンストラクターや要素の各インスタンスでプロパティ値を設定するのではなく、この方法を使用するようにしてください。Use this technique rather than setting the property value in a constructor or on each instance of an element.

Register を使用して PropertyMetadata の値を設定するSet the PropertyMetadata Value using Register

を作成するDependencyProperty際に、PropertyMetadataRegisterまたはOverrideMetadataメソッドを使用して を設定するオプションがあります。When creating a DependencyProperty, you have the option of setting the PropertyMetadata using either the Register or OverrideMetadata methods. オブジェクトには静的コンストラクターを呼び出すOverrideMetadata場合がありますが、これは最適なソリューションではなく、パフォーマンスに影響します。Although your object could have a static constructor to call OverrideMetadata, this is not the optimal solution and will impact performance. 最高のパフォーマンスを得るためにPropertyMetadataは、呼びRegister出し中に を に設定します。For best performance, set the PropertyMetadata during the call to Register.

Freezable オブジェクトFreezable Objects

AFreezableは、フリーズ解除とフリーズの 2 つの状態を持つ特殊なタイプのオブジェクトです。A Freezable is a special type of object that has two states: unfrozen and frozen. 可能な場合は常にオブジェクトを固定するようにすると、アプリケーションのパフォーマンスが向上し、作業セットを縮小できます。Freezing objects whenever possible improves the performance of your application and reduces its working set. 詳細については、「Freezable オブジェクトの概要」を参照してください。For more information, see Freezable Objects Overview.

それぞれにFreezableChanged変更されるたびに発生するイベントがあります。Each Freezable has a Changed event that is raised whenever it changes. ただし、変更通知はアプリケーションのパフォーマンスに影響を与えます。However, change notifications are costly in terms of application performance.

それぞれがRectangle同じBrushオブジェクトを使用する次の例を考えてみます。Consider the following example in which each Rectangle uses the same Brush object:

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

既定では、WPFWPFSolidColorBrushオブジェクトのFillプロパティを無効にするために、オブジェクトのChangedイベントのイベント ハンドラーをRectangle提供します。By default, WPFWPF provides an event handler for the SolidColorBrush object's Changed event in order to invalidate the Rectangle object's Fill property. この場合、イベントSolidColorBrushを発生Changedさせるたびに、コールバック関数を呼Rectangleび出す必要があります。In this case, each time the SolidColorBrush has to fire its Changed event it is required to invoke the callback function for each Rectangle—the accumulation of these callback function invocations impose a significant performance penalty. さらに、この時点でハンドラーを追加または削除すると、アプリケーションでリスト全体を検査しなければならなくなるため、パフォーマンスに大きく影響します。In addition, it is very performance intensive to add and remove handlers at this point since the application would have to traverse the entire list to do so. アプリケーション シナリオでSolidColorBrushを変更しない場合は、イベント ハンドラを不必要にChanged保守するコストを支払います。If your application scenario never changes the SolidColorBrush, you will be paying the cost of maintaining Changed event handlers unnecessarily.

aFreezableを凍結すると、変更通知の維持にリソースを費やす必要がなくなるため、パフォーマンスが向上します。Freezing a Freezable can improve its performance, because it no longer needs to expend resources on maintaining change notifications. 次の表は、プロパティSolidColorBrushIsFrozenが に設定されている場合の単純なtrueサイズを示しています。The table below shows the size of a simple SolidColorBrush when its IsFrozen property is set to true, compared to when it is not. これは、10Rectangle個のオブジェクトFillのプロパティに 1 つのブラシを適用することを前提としています。This assumes applying one brush to the Fill property of ten Rectangle objects.

状態State サイズSize
冷凍SolidColorBrushFrozen SolidColorBrush 212 バイト212 Bytes
非凍結SolidColorBrushNon-frozen SolidColorBrush 972 バイト972 Bytes

この概念の例を次のコード サンプルに示します。The following code sample demonstrates this concept:

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;
}
Dim frozenBrush As Brush = New SolidColorBrush(Colors.Blue)
frozenBrush.Freeze()
Dim nonFrozenBrush As Brush = New SolidColorBrush(Colors.Blue)

For i As Integer = 0 To 9
    ' Create a Rectangle using a non-frozed Brush.
    Dim rectangleNonFrozen As New Rectangle()
    rectangleNonFrozen.Fill = nonFrozenBrush

    ' Create a Rectangle using a frozed Brush.
    Dim rectangleFrozen As New Rectangle()
    rectangleFrozen.Fill = frozenBrush
Next i

固定されていない Freezable の Changed ハンドラーによってオブジェクトが維持される可能性があるChanged Handlers on Unfrozen Freezables may Keep Objects Alive

オブジェクトがFreezableオブジェクトのChangedイベントに渡すデリゲートは、実質的にそのオブジェクトへの参照です。The delegate that an object passes to a Freezable object's Changed event is effectively a reference to that object. したがって、Changedイベント ハンドラーは、オブジェクトを予想よりも長く存続させることができます。Therefore, Changed event handlers can keep objects alive longer than expected. オブジェクトのFreezableChangedイベントをリッスンするために登録されているオブジェクトのクリーンアップを実行する場合、オブジェクトを解放する前にそのデリゲートを削除することが重要です。When performing clean up of an object that has registered to listen to a Freezable object's Changed event, it is essential to remove that delegate before releasing the object.

WPFWPFまた、イベントをChanged内部的にフックします。also hooks up Changed events internally. たとえば、値として受け取るFreezableすべての依存関係プロパティは、イベントChangedを自動的にリッスンします。For example, all dependency properties which take Freezable as a value will listen to Changed events automatically. このFill概念を示すBrushプロパティは、 を使用します。The Fill property, which takes a Brush, illustrates this concept.

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

myBrushの代入myRectangle.Fillで、Rectangleオブジェクトを指し示すデリゲートがオブジェクトのSolidColorBrushChangedイベントに追加されます。On the assignment of myBrush to myRectangle.Fill, a delegate pointing back to the Rectangle object will be added to the SolidColorBrush object's Changed event. このため、次のコードを使用しても、myRect は実際にはガベージ コレクションの対象にはなりません。This means the following code does not actually make myRect eligible for garbage collection:

myRectangle = null;
myRectangle = Nothing

この場合myBrush、まだ生きmyRectangle続けており、Changedイベントを発生させるときにコールバックします。In this case myBrush is still keeping myRectangle alive and will call back to it when it fires its Changed event. newRectangleFillプロパティmyBrushに割り当てると、単に別のイベントmyBrushハンドラが に追加されることに注意してください。Note that assigning myBrush to the Fill property of a new Rectangle will simply add another event handler to myBrush.

これらの種類のオブジェクトをクリーンアップする推奨される方法は、BrushFillプロパティからを削除することです。 ChangedThe recommended way to clean up these types of objects is to remove the Brush from the Fill property, which will in turn remove the Changed event handler.

myRectangle.Fill = null;
myRectangle = null;
myRectangle.Fill = Nothing
myRectangle = Nothing

ユーザー インターフェイスの仮想化User Interface Virtualization

WPFWPFまた、データ バインド子StackPanelコンテンツを自動的に 「仮想化」する要素のバリエーションも提供します。also provides a variation of the StackPanel element that automatically "virtualizes" data-bound child content. ここで、"仮想化" は、どの項目を画面に表示するかに基づいて、オブジェクトのサブセットを多数のデータ項目から生成する手法を指します。In this context, the word virtualize refers to a technique by which a subset of objects are generated from a larger number of data items based upon which items are visible on-screen. 特定の時間に画面に UI 要素が少ししか表示されていない場合に多数の UI 要素を生成すると、メモリおよびプロセッサの両方に負荷がかかります。It is intensive, both in terms of memory and processor, to generate a large number of UI elements when only a few may be on the screen at a given time. VirtualizingStackPanel( によって提供されるVirtualizingPanel機能を通じて ) は、ItemContainerGenerator表示可能ItemsControlな項目をListBox計算ListViewし、 ( または など ) から 、 を使用して、可視項目の要素のみを作成します。VirtualizingStackPanel (through functionality provided by VirtualizingPanel) calculates visible items and works with the ItemContainerGenerator from an ItemsControl (such as ListBox or ListView) to only create elements for visible items.

パフォーマンスの最適化の一環として、これらの項目のビジュアル オブジェクトは、画面に表示される場合にのみ生成または維持されます。As a performance optimization, visual objects for these items are only generated or kept alive if they are visible on the screen. 既にコントロールの表示可能領域にないビジュアル オブジェクトは削除される可能性があります。When they are no longer in the viewable area of the control, the visual objects may be removed. これをデータの仮想化と混同しないようにしてください。データの仮想化では、すべてのデータ オブジェクトがローカル コレクションに存在するのではなく、データ オブジェクトが必要に応じてストリームされます。This is not to be confused with data virtualization, where data objects are not all present in the local collection- rather streamed in as needed.

次の表は、 と に 5000TextBlock個のStackPanel要素を追加およびVirtualizingStackPanelレンダリングする経過時間を示しています。The table below shows the elapsed time adding and rendering 5000 TextBlock elements to a StackPanel and a VirtualizingStackPanel. このシナリオでは、測定は、パネル要素がテキスト文字列を表示する時間にItemsSourceItemsControlオブジェクトのプロパティにテキスト文字列をアタッチする時間を表します。In this scenario, the measurements represent the time between attaching a text string to the ItemsSource property of an ItemsControl object to the time when the panel elements display the text string.

ホスト パネルHost panel レンダリング時間 (ミリ秒)Render time (ms)
StackPanel 32103210
VirtualizingStackPanel 4646

関連項目See also