在什么场景下冻结 WPF 对象对性能有很大的好处?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/799911/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In what scenarios does freezing WPF objects benefit performance greatly?
提问by Drew Noakes
Many types in WPF derive from Freezable
. It provides immutability to mutable POCO objects and, apparently, allows for improved performance in certain situations.
WPF 中的许多类型都源自Freezable
. 它为可变 POCO 对象提供了不变性,并且显然可以在某些情况下提高性能。
Has anyone found that freezing objects within their WPF application has greatly improved performance? If so, then which items gave the biggest performance difference when being frozen?
有没有人发现在他们的 WPF 应用程序中冻结对象大大提高了性能?如果是这样,那么哪些物品在被冻结时性能差异最大?
(Note that I have posted a similar but different questiontoo)
(请注意,我也发布了一个类似但不同的问题)
回答by
You might be interested in my experiences with Freezable:
您可能对我使用 Freezable 的经验感兴趣:
I once wrote a PDF viewer using muPdf which renders bitmaps, that I render with WPF. What helps performance greatly is that I can render the page bitmaps on a background thread, freeze them, and then pass them to the UI thread. It is nice that WPF does not copy the image to freeze it, but the ability to do all this preparation on a background thread was the key benefit for me.
我曾经使用 muPdf 编写了一个 PDF 查看器,它呈现位图,我用 WPF 呈现。对性能有很大帮助的是我可以在后台线程上渲染页面位图,冻结它们,然后将它们传递给 UI 线程。WPF 不会复制图像来冻结它,这很好,但是能够在后台线程上完成所有这些准备工作对我来说是主要的好处。
From what I understand, all visuals need to be frozen so they can be safely rendered by the WPF render thread. If you render large unfrozen visuals, they will get cloned to frozen ones when WPF renders them. If you freeze your static bitmaps beforehand, WPF can just share the pointer with the render thread without cloning. Unfrozen objects may even get copied repeatedly if WPF is not aware wether the object is changed from the last time it was rendered. Frozen objects eliminate the need for all this copying.
据我了解,所有视觉效果都需要冻结,以便 WPF 渲染线程可以安全地渲染它们。如果渲染大型未冻结的视觉效果,当 WPF 渲染它们时,它们将被克隆为冻结的视觉效果。如果事先冻结静态位图,WPF 可以只与渲染线程共享指针,而无需克隆。如果 WPF 不知道对象是否从上次呈现时发生了更改,则解冻对象甚至可能会被重复复制。冻结对象消除了所有这些复制的需要。
回答by CSharper
These potential memory leaks could happen if you use the Image control (and not use Freeze method):
如果您使用 Image 控件(而不是使用 Freeze 方法),可能会发生这些潜在的内存泄漏:
a) You use BitmapImage as the Image source and do not release the BitmapImage:
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) You assign multiple BitmapImage as the Image source and do not release all of the BitmapImage you used (similar to (a)). This one introduced in .Net 3.5:
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);
Source: WPF Performance
资料来源:WPF 性能
回答by Manish Basantani
Though you have already accepted the answer, just wanted to log a different version of the answer that helped me better.
尽管您已经接受了答案,但只是想记录对我有帮助的不同版本的答案。
From MSDN(minor edit):
来自MSDN(小编辑):
If you were to modify control holding reference to unmanaged low-level resources (eg: Brush), every modification would have to regenerated those low-level objects!
The freezable class is what gives a brush the ability to find its corresponding generated, low-level objects and to update them when it changes. When this ability is enabled, the brush is said to be "unfrozen."
A freezable's Freeze method enables you to disable this self-updating ability. You can use this method to make the brush become "frozen," or unmodifiable. Thus, improving performance.
如果您要修改控制对非托管低级资源的引用(例如:Brush),则每次修改都必须重新生成这些低级对象!
freezable 类使画笔能够找到相应的生成的低级对象,并在发生变化时更新它们。启用此功能后,刷子被称为“解冻”。
freezable 的 Freeze 方法使您能够禁用此自我更新功能。您可以使用此方法使画笔“冻结”或不可修改。从而提高性能。
And, the code to explain the usage:
并且,解释用法的代码:
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;
}
回答by Chromozon
I developed a high-performance image viewer application. We had code on the back-end that created a new bitmap every frame and wrote that bitmap to the screen like so:
我开发了一个高性能的图像查看器应用程序。我们在后端有代码,每帧创建一个新的位图,并将该位图写入屏幕,如下所示:
Writeablebitmap wb = new WriteableBitmap();
// < code to set the wb pixel values here >
// Push the bitmap to the screen
image.Source = wb;
During testing, we noticed that there was a terrible flickering while going 30+ FPS with moderately-sized images (1080p). The fix? Just freeze the bitmap before setting it to the image.Source. No more product-killing performance bug. Nowadays I try to freeze everything I can.
在测试过程中,我们注意到在以 30+ FPS 处理中等大小的图像 (1080p) 时出现了可怕的闪烁。修复?只需在将位图设置为 image.Source 之前冻结位图。不再有杀死产品的性能错误。现在我试图冻结我所能做的一切。