WPF中的许多类型都来自Freezable
。它为可变POCO对象提供了不变性,并且显然允许在某些情况下提高性能。在什么情况下冻结WPF对象极大地有利于性能?
有没有人发现,在他们的WPF应用程序中冻结对象已经大大提高了性能?如果是这样,那么哪些项目在冻结时会产生最大的性能差异?
(请注意,我已经发布了similar but different question太)
WPF中的许多类型都来自Freezable
。它为可变POCO对象提供了不变性,并且显然允许在某些情况下提高性能。在什么情况下冻结WPF对象极大地有利于性能?
有没有人发现,在他们的WPF应用程序中冻结对象已经大大提高了性能?如果是这样,那么哪些项目在冻结时会产生最大的性能差异?
(请注意,我已经发布了similar but different question太)
您可能会感兴趣我的经验与可冻结:
我曾经使用muPdf这使得位图,我写了一个PDF阅读器使用WPF呈现。最重要的是,我可以在后台线程上呈现页面位图,冻结它们,然后将它们传递给UI线程。很高兴WPF不会复制图像来冻结它,但是在后台线程上完成所有这些准备的能力对我来说是关键的好处。
据我所知,所有的视觉效果需要被冻结,以便WPF渲染线程可以安全地渲染它们。如果您渲染大型解冻视觉效果,当WPF呈现它们时,它们将被克隆为冻结视觉效果。如果您事先冻结您的静态位图,WPF可以与渲染线程共享指针而不进行克隆。如果WPF不知道对象是否从上次渲染时发生更改,则未冻结的对象甚至可能会被重复复制。冻结的对象消除了所有这些复制的需要。
如果使用Image控件(而不是用冷冻法)这些潜在的内存泄漏可能发生:
一)使用的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);
我假设你指的是这里描述的情况:https://blogs.msdn.microsoft.com/jgoldb/2008/02/04/finding-memory-leaks-in-wpf-based-applications/(你应该把你的答案中的具体链接)。我认为值得指出的是,在这些场景中冻结位图只是解决从根本上被认为是坏主意的方法,即使用“静态”字段来存储随后的位图在一个`Image`对象中引用。 – 2016-09-26 00:17:31
`Image`对象必须订阅更改事件,因此位图保留了强引用,阻止了`Image`的GC,当然还有任何订阅了_its_更改事件的GC。这实际上是一个更广泛的问题,编写事件驱动代码的人需要注意:如果这些对象是由事件字段间接引用的,则“static”字段可以对整个对象树进行根。冻结位图有其他原因,但更好的解决方法是在不再需要位图对象的时候(例如关闭窗口时)不要在静态字段中放置位图对象。 – 2016-09-26 00:17:35
虽然你已经接受了答案,但只是想记录不同版本的答案,帮助我更好。
从MSDN(次要编辑):
如果你要修改的控制保持基准非托管的低级别资源(例如:刷),每次修改将不得不重新生成这些低级别的对象!
冻结类是什么让刷子的能力 找到其相应的生成的低级别的对象,并更新 他们改变时。当这种能力被启用时,画笔被称为 被“解冻”。
冻结的冻结方法使您可以禁用此自我更新的能力。您可以使用此方法使画笔变得“冻结”,或不可修改。因此,提高性能。
而且,代码解释用法:
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;
在测试过程中,我们注意到,有一个可怕的闪烁,同时要30+的FPS适度大小的图像(1080p)。修复?在将其设置为图像之前,冻结位图。没有更多的产品查杀性能错误。现在我试着冻结我所能做的一切。
非常有帮助谢谢。我没有意识到你可以在后台线程上做到这一点,应该帮助我的一个应用程序相当大! – Kelly 2017-05-19 00:00:00