在什么情况下冻结 WPF 对象对性能有很大好处?

发布于 2024-07-17 11:27:59 字数 245 浏览 8 评论 0原文

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

有没有人发现冻结 WPF 应用程序中的对象可以极大地提高性能? 如果是这样,那么哪些物品在冷冻时表现出最大的性能差异?

(请注意,我也发布了一个类似但不同的问题

Many types in WPF derive from Freezable. It provides immutability to mutable POCO objects and, apparently, allows for improved performance in certain situations.

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?

(Note that I have posted a similar but different question too)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

始于初秋 2024-07-24 11:27:59

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

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

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

You might be interested in my experiences with 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.

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.

泪意 2024-07-24 11:27:59

如果您使用 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 性能

These potential memory leaks could happen if you use the Image control (and not use Freeze method):

a) You use BitmapImage as the Image source and do not release the 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:

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

思念满溢 2024-07-24 11:27:59

尽管您已经接受了答案,但只是想记录一个不同版本的答案,以更好地帮助我。

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

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):

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.

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;
            }
关于从前 2024-07-24 11:27:59

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

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。 不再有破坏产品的性能错误。 现在我试着冷冻一切我能冷冻的东西。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文