WPF 中的许多类型都派生自Freezable
. 它为可变 POCO 对象提供了不变性,并且显然可以在某些情况下提高性能。
有没有人发现在他们的 WPF 应用程序中冻结对象大大提高了性能?如果是这样,那么在冻结时哪些项目的性能差异最大?
(请注意,我也发布了一个类似但不同的问题)
WPF 中的许多类型都派生自Freezable
. 它为可变 POCO 对象提供了不变性,并且显然可以在某些情况下提高性能。
有没有人发现在他们的 WPF 应用程序中冻结对象大大提高了性能?如果是这样,那么在冻结时哪些项目的性能差异最大?
(请注意,我也发布了一个类似但不同的问题)
您可能对我使用 Freezable 的经历感兴趣:
我曾经使用 muPdf 编写了一个 PDF 查看器,它呈现位图,我用 WPF 呈现。对性能有很大帮助的是,我可以在后台线程上渲染页面位图,冻结它们,然后将它们传递给 UI 线程。WPF 不会复制图像来冻结它,这很好,但是在后台线程上完成所有这些准备工作的能力对我来说是关键的好处。
据我了解,所有视觉效果都需要冻结,以便 WPF 渲染线程可以安全地渲染它们。如果您渲染大型未冻结的视觉对象,它们将在 WPF 渲染它们时被克隆为冻结的视觉对象。如果您事先冻结静态位图,WPF 可以只与渲染线程共享指针而无需克隆。如果 WPF 不知道对象自上次呈现时是否发生更改,则解冻的对象甚至可能会被重复复制。冻结对象消除了所有这些复制的需要。
如果您使用 Image 控件(而不使用 Freeze 方法),可能会发生这些潜在的内存泄漏:
a) 您使用 BitmapImage 作为 Image 源并且不释放 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 作为 Image 源,并且不释放您使用的所有 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 性能
尽管您已经接受了答案,但只是想记录对我有更好帮助的答案的不同版本。
来自MSDN(小编辑):
如果您要修改对非托管低级资源(例如:画笔)的控制持有引用,则每次修改都必须重新生成那些低级对象!
可冻结类使画笔能够找到其相应生成的低级对象并在更改时更新它们。启用此功能后,笔刷被称为“解冻”。
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;
}
我开发了一个高性能的图像查看器应用程序。我们在后端有代码,每帧创建一个新的位图,并将该位图写入屏幕,如下所示:
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 之前冻结位图。没有更多的产品性能错误。现在我试着冷冻我能做的一切。