在什么情况下,冻结WPF对象会大大提高性能?

时间:2009-04-28 21:31:18

标签: wpf performance freeze freezable

WPF中的许多类型派生自Freezable。它为可变POCO对象提供了不变性,显然可以在某些情况下提高性能。

有没有人发现WPF应用程序中的冻结对象大大提高了性能?如果是这样,那么哪些项目在冻结时会产生最大的性能差异?

(请注意,我也发布了similar but different question

4 个答案:

答案 0 :(得分:51)

您可能对我使用Freezable的经历感兴趣:

我曾经使用muPdf编写了一个PDF查看器,它渲染了我用WPF渲染的位图。有助于提高性能的是我可以在后台线程上呈现页面位图,冻结它们,然后将它们传递给UI线程。 WPF不会复制图像以冻结它是很好的,但是在后台线程上完成所有这些准备的能力对我来说是关键的好处。

据我了解,所有视觉效果都需要冻结,以便WPF渲染线程可以安全地呈现它们。如果渲染大量未冻结的视觉效果,当WPF呈现它们时,它们将被克隆到冻结的视觉效果中。如果事先冻结静态位图,WPF只能与渲染线程共享指针而不进行克隆。如果WPF不知道对象是否从上次渲染时更改,则未冻结的对象甚至可能会被重复复制。冻结的对象消除了所有这些复制的需要。

答案 1 :(得分:18)

如果使用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 Performance

答案 2 :(得分:13)

虽然你已经接受了答案,但只是想记录一个不同版本的答案,这对我帮助更大。

来自MSDN(次要编辑):

  

如果要修改对非托管低级资源(例如:Brush)的控制保持引用,则每次修改都必须重新生成那些低级对象!

     

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

答案 3 :(得分:4)

我开发了一个高性能的图像查看器应用程序。我们在后端有代码,每帧都创建一个新的位图,并将该位图写入屏幕,如下所示:

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。没有更多的产品杀死性能错误。现在我试着冻结我所能做的一切。