web-dev-qa-db-ja.com

WPFオブジェクトの凍結はパフォーマンスにどのようなシナリオで大きなメリットをもたらしますか?

WPFの多くの型はFreezableから派生しています。変更可能なPOCOオブジェクトに不変性を提供し、明らかに、特定の状況でパフォーマンスを向上させることができます。

WPFアプリケーション内でオブジェクトを凍結するとパフォーマンスが大幅に向上することを誰かが発見しましたか?もしそうなら、どのアイテムが凍結されたときに最大のパフォーマンスの違いをもたらしましたか?

(私は 似ているが別の質問 も投稿したことに注意してください)

46
Drew Noakes

あなたは私のFreezableでの経験に興味があるかもしれません:

私はかつて、ビットマップをレンダリングするmuPdfを使用してWPFでレンダリングするPDFビューアを記述しました。パフォーマンスを大幅に向上させるのは、バックグラウンドスレッドでページビットマップをレンダリングし、フリーズして、 WPFが画像をコピーしてフリーズしないのはいいことですが、このすべての準備をバックグラウンドスレッドで実行できることは、私にとって主な利点でした。

私の理解から、WPFレンダリングスレッドによって安全にレンダリングできるように、すべてのビジュアルを凍結する必要があります。フリーズされていない大きなビジュアルをレンダリングする場合、WPFがそれらをレンダリングすると、フリーズされたビジュアルに複製されます。静的ビットマップを事前に凍結しておけば、WPFは複製せずに、レンダリングスレッドとポインターを共有できます。オブジェクトが最後にレンダリングされたときから変更されているかどうかをWPFが認識していない場合、フリーズされていないオブジェクトは繰り返しコピーされることさえあります。凍結されたオブジェクトは、このすべてのコピーの必要性を排除します。

51
user180326

これらの潜在的なメモリリークは、Imageコントロールを使用している(そしてFreezeメソッドを使用していない)場合に発生する可能性があります。

a)画像ソースとしてBitmapImageを使用し、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)複数のBitmapImageを画像ソースとして割り当て、使用したすべてのBitmapImageを解放しない((a)と同様)。これは.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);

ソース: WPFパフォーマンス

18
CSharper

あなたはすでに答えを受け入れましたが、私をより良くするのに役立つ別のバージョンの答えを記録したかっただけです。

From [〜#〜] msdn [〜#〜] (マイナー編集):

アンマネージ低レベルリソース(例:ブラシ)への参照を保持するコントロールを変更する場合、すべての変更でそれらの低レベルオブジェクトを再生成する必要があります。

Freezableクラスは、対応する生成された低レベルのオブジェクトを見つけ、変更時にそれらを更新する機能をブラシに与えるものです。この機能が有効になっている場合、ブラシは「凍結されていない」と言います。

FreezableのFreezeメソッドを使用すると、この自己更新機能を無効にすることができます。このメソッドを使用して、ブラシを「フリーズ」または変更不可にすることができます。したがって、パフォーマンスが向上します。

そして、使用法を説明するコード:

            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;
            }
13

高性能な画像ビューアアプリケーションを開発しました。フレームごとに新しいビットマップを作成し、そのビットマップを次のように画面に書き込んだバックエンドのコードがあります。

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

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

テスト中に、適度なサイズの画像(1080p)で30以上のFPSに移行すると、ひどいちらつきが発生することがわかりました。修正? image.Sourceに設定する前にビットマップをフリーズしてください。製品を殺すパフォーマンスのバグはもうありません。今日、私はできる限りすべてを凍結しようとしています。

4
Chromozon