WPF_性能优化

WPF(Windows Presentation Foundation)是微软推出的基于Windows的用户界面框架,运行在 .NET Framework 3.0及以上版本。WPF是基于DirectX引擎的,支持GPU硬件加速,在不支持硬件加速时也可以使用软件绘制。尽管WPF有诸多优点,有时我们还是会遇到性能问题,比如界面卡顿,内存泄漏等等。针对WPF程序的性能优化是一个宽泛的问题,本文是对我们这段时间以来所作工作的一个总结。

图形硬件

相同的程序在不同的硬件上运行,会有不同的表现。对渲染能力影响比较大的硬件特性为:

  • Video RAM - 现存的数量决定合成图形的缓冲区的大小和数量。
  • Pixel Shader - 像素着色器决定了像素计算能力。根据图形的分辨率不同,每帧可能需要处理几百万个像素。
  • Vertex Shader - 顶点着色器用于计算图形的顶点数据。
  • Multitexture Support - 多重纹理支持是指在3D图形的混合操作中应用两个或更多不同纹理的能力。

代码规范

在程序开发过程中制定一些代码规范,可以让我们避免一些性能问题的坑。

1.让 VisualTree 尽量简单

在屏幕上绘制图形时,每个元素的布局被调用两次(measure & arrange)。布局过程是一个数学密集型的过程,子元素的数量越多,需要的计算次数就越多。

2.虚拟化你的 ItemControls

ItemsControls往往会增加 VisualTree 的深度,如果没有虚拟化会频繁地创建和销毁元素。使用 VirtualizingStackPanel 作为宿主,并设置 VirtualizationMode=Recycling 以便重用元素的容器。

3.尽可能使用 StaticResources

DynamicResources 会创建一个临时表达式并推迟对资源的查找,当真正需要资源值时才去请求,其查找方式和运行时查找相同,这会对性能产生影响。

4.通过 Brushes 设置透明度

如果使用 Brush 来填充元素,那么最好设置 Brush 的透明度而不是设置 Element 的透明度。当修改 Element 的透明度时会导致WPF重绘。

5.避免使用 run 来设置Text属性

<TextBlock>
    <Run Text="F"/>
    <Run Text="W"/>
TextBlock>

6.StreamGeometry对象比PathGeometry更轻量级

StreamGeometry在处理多个PathGeometry对象时进行了优化,消耗更小的内存,有更高的性能表现。

7.使用缩小尺寸的图像

如果程序需要显示更小的缩略图,那么创建缩小尺寸的图像版本会提高性能。

8.BitMapScalingMode

默认情况下,WPF使用高质量的图像重采集算法,会导致帧率下降和动画断断续续。设置 LowQuality 切换到速度优化算法可以提高性能。

9.Freeze Freezables

可冻结对象是一种特殊类型的对象,具有两种状态:未冻结和已冻结。比如 Brush,Geometry,冻结对象可以提高性能并减少内存消耗。

10.修正绑定错误

绑定错误是WPF程序中最常见的性能问题原因,每次发生绑定错误都会执行一次 perf 命中并尝试解决错误。

11.避免绑定到 Label.Content

把string绑定到 Label.Content时会导致较差的性能。每次数据变动时,旧的string对象会被丢弃并创建一个新的string对象。可以替换为 TextBlock.Text 属性。

12.使用 IList 作为 ItemsControls 数据源

当绑定 IEnumerable数据作为 ItemsControl数据源时,WPF会重新包装为 IList 类型。

13.UI线程只做简单的事情

不要在UI线程上做耗时的动作,UI线程只用来更新界面。

14.降低动画的帧率

通过设置 Storyboard.DesiredFrameRate 降低动画的帧率。

15.内存泄漏

内存泄漏也会降低程序性能,这块内容比较多,后面会单独篇幅中介绍。

性能分析工具

当我们的程序开发完成后仍然存在性能问题,这时就要用到性能分析工具来帮助我们分析应用程序的运行时行为,并确定可以应用的性能优化的类型。比较常用的工具有:

  • Snoop - 可以查看可视化对象的数量
  • WPFPerf - WPF提供的套件
  • Ants Performance Profiler
  • dotTrace - 函数运行时长
  • dotMemory - 内存占用情况

不同的软件,使用方法和侧重点会有区别,可以真实使用并分析总结一下。下面对 dotTrace 做一个简单的介绍。

dotTrace

运行程序,打开dotTrace,我们就可以把进程附加到dotTrace上。运行一段时间,获取运行时情况快照来分析具体耗时情况。
WPF_性能优化_第1张图片

如果是调试程序,还可以联动代码,非常的方便。

找到耗时较长的代码,我们就可以针对性的对某个方法进行优化。比如针对一个通过反射动态获取字段的代码块,优化前后的对比如下:

WPF_性能优化_第2张图片

比如一个 string.Split() 方法的优化:

WPF_性能优化_第3张图片

string.Split() 方法内部会自动转换成 char[] 类型,如果能直接传入 char[] 类型会减少方法的耗时。

像上面对方法的优化还有很多,我们最好对照 dotTrace 报表为每一个耗时方法都去分析为什么耗时?还可以怎么优化?

UI线程

在上面的分析做完之后,我们发现有个窗口还是占用比较高的耗时和CPU。这是一个第三方的图表控件 DevExpress ,用来刷新波动率图像。在尝试优化使用方法后,还是决定自己封装插件进行图像的绘制。我们把图像上所用到的元素分类抽象出来:

WPF_性能优化_第4张图片
使用dotTrace来分析对比两个控件的性能:

WPF_性能优化_第5张图片

DevExpress拥有.NET开发需要的平台控件,包含600多个UI控件、报表平台等一系列辅助工具,可为桌面、Web和移动应用提供直观的解决方案。

内存泄漏

dotMemory 是一个 .NET 的内存分析工具,可以帮助你优化 .NET 应用的内存使用,找出内存泄漏和其他的内存使用问题.

WPF_性能优化_第6张图片
内存泄漏是一个内容比较多的主题,我们会有另外一篇文章具体来总结这方面的工作。最简单使用场景:

  • 可以对内存占用比较多的模块进行优化
  • 关闭窗口,查看内存是否仍然存在
  • 程序正常运行一段时间,查看内存变化情况

程序性能的优化是一个长周期的工作,我们也会持续的进行。本次比较笼统的总结了我们这段时间以来的工作,希望对你有所帮助。

我的公众号

WPF_性能优化_第7张图片

你可能感兴趣的:(WPF,wpf,c#,wpf)