В каких случаях замораживание объектов WPF значительно повышает производительность? - PullRequest
46 голосов
/ 29 апреля 2009

Многие типы в WPF происходят от Freezable. Он обеспечивает неизменность для изменяемых объектов POCO и, по-видимому, позволяет повысить производительность в определенных ситуациях.

Кто-нибудь обнаружил, что замораживание объектов в их приложении WPF значительно улучшило производительность? Если да, то какие предметы дают наибольшую разницу в производительности при замораживании?

(Обратите внимание, что я отправил похожий, но другой вопрос тоже)

Ответы [ 4 ]

51 голосов
/ 07 марта 2010

Вас может заинтересовать мой опыт работы с Freezable:

Однажды я написал программу просмотра PDF с использованием muPdf, который отображает растровые изображения, которые я отображаю с помощью WPF. Производительность сильно влияет на то, что я могу отображать растровые изображения страниц в фоновом потоке, замораживать их, а затем передавать их в поток пользовательского интерфейса. Хорошо, что WPF не копирует изображение, чтобы заморозить его, но возможность сделать всю эту подготовку в фоновом потоке была для меня ключевым преимуществом.

Из того, что я понимаю, все визуальные элементы должны быть заморожены, чтобы они могли безопасно отображаться потоком рендеринга WPF. Если вы визуализируете большие незамерзающие визуальные эффекты, они будут клонированы к замороженным, когда их визуализирует WPF. Если вы заранее заморозите свои статические растровые изображения, WPF может просто поделиться указателем с потоком рендеринга без клонирования. Незамороженные объекты могут даже копироваться повторно, если WPF не знает, изменяется ли объект с момента последнего отображения. Замороженные объекты исключают необходимость всего этого копирования.

18 голосов
/ 29 апреля 2009

Эти потенциальные утечки памяти могут произойти, если вы используете элемент управления изображением (а не метод 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

13 голосов
/ 14 марта 2012

Хотя вы уже приняли ответ, просто хотели записать другую версию ответа, которая помогла мне лучше.

С MSDN (незначительное редактирование):

Если бы вы изменили ссылку удержания элемента управления на неуправляемые низкоуровневые ресурсы (например, Brush), каждая модификация должна была бы регенерировать эти низкоуровневые объекты!

Класс freezable - это то, что дает кисти возможность найти соответствующие ему сгенерированные низкоуровневые объекты и обновить их, когда это меняется. Когда эта способность включена, кисть говорит быть "незамерзшим".

Метод Freezeable 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;
            }
4 голосов
/ 21 января 2017

Я разработал высокопроизводительное приложение для просмотра изображений. У нас был код на сервере, который создавал новое растровое изображение каждый кадр и записывал это растровое изображение на экран следующим образом:

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

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

Во время тестирования мы заметили ужасное мерцание при скорости 30 кадров в секунду и изображениях среднего размера (1080p). Исправление? Просто заморозьте растровое изображение, прежде чем устанавливать его в image.Source. Нет больше ошибки производительности убийства продукта. Сейчас я пытаюсь заморозить все, что могу.

...