避坑OutOfMemory - WPF程序性能优化二

 

Point1:及时释放MediaElement

MediaElement调用的系统Windows Media Player.  WMP播放不出来的视频,在WPF程序里也会播不出来。 事实上MediaPlayer挺费内存和GPU的, UserControl.Unloaded中一定要及时释放播放器,否则最常见的问题,视频不显示了,但是视频声音还在。

Tips:

有时候明明是常见的.mp4.  .wmv视频文件,其他播放器能正常播放,但是在Windows Media Player中无法播放,WPF程序里也没法播放,崩着急, 检查下视频编码。  比如.mp4文件的编码就有:Divx;Xvid; H264; H265。  wmv编码有:WMV1,WMV2,WMV3, WMV9。 移动端以及浏览器端支持最好的视频格式为.H264编码、 音频编码.AAC的mp4文件。若WPF中无法播放mp4. wmv或其他格式视频,可以尝试对视频进行格式转换、变化下编码。

 

Point2:尽量用DispatcherTimer替代CompositionTarget.Rendering

CompositionTarget.Rendering在使用时,若GPU、CPU耗费较高,鼠标滑动一下,都能感觉出程序节奏的明显不稳定。

比如在做内容滚动时,推荐使用DispatchTimer。

 

Point3:大量UI对象需要创建或者加载

数量级超大时,用虚拟化的方式实现,例ListBox的虚拟化技术,最常见的就是Office中的Word,上百页的文档滚动时,不采用虚拟化技术的话,绝对卡死。 

数量级还凑合的时候,可以适当设置条件,例:200张小图片。  窗口界面就那么大,能显示的内容有限, 界面暂时不呈现的,先以*.children.remove(*)方式移除。 例我开源项目 https://github.com/DuelWithSelf/WPFEffects  中的:Carousel3D。  一定角度范围内的才 使用*.Children.Add(*)。 即保证当前窗口需要呈现的内容添加到界面就行,一旦不显示了,立即移除。 减少UI线程的渲染耗能。我的Demo效果如下:

这个Demo我后面又优化了,后续逐步更新至Github。  不在窗口前端呈现时,连Image所在的UserControl对象都不需要创建。页面打开时,相当于只创建了5、6个元素块添加到界面, 滑动到哪,创建到哪。   否则一下创建出所有的对象添加至界面,性能不好时程序能卡半天。 

数量级较大时,延时创建和加载非常有必要。最简单的测试:
private List<string> ImgItems = new List<string>();

private void DoLoadUIElement()
{
    for (int i = 0; i < 100; i++)
        ImgItems.Add("FileName" + i);

    Task.Run(async () =>
    {
        for (int i = 0; i < ImgItems.Count; i++)
        {
            if (ImgItems != null)
            {
                await Task.Delay(100);
                await this.Dispatcher.BeginInvoke((Action)(() =>
                {
                    DoCreateUIElement(i);
                }));
            }
        }
    });
}

private void DoCreateUIElement(int nIndex)
{
    string str = this.ImgItems[nIndex];
    Console.WriteLine("Create Time(Millisecond):" + DateTime.Now.Millisecond + "  Create Element:" + str );
}

可以拷贝上述代码,试一下。输出如下,界面Loaded时,有效的将要一次性创建显示的内容通过延时处理分散下, 否则CPU、GPU爆发力不够的话,界面卡是一定得。

Point5: WPF中图片加载

WPF应用打包后,你会发现,几万行代码打包出来也就几M的大小,但是程序中若嵌入了图片, 那最终的exe肯定不会太小。适当的图片压缩很有必要,图片质量越高,对显卡性能要求也就越高。 一般的电脑分辨率也就1920*1080. 不做专业看图模块的话, 图片资源的分辨率高于这个比例,其实是没多少必要的。 大于300M以上的高质量图片,WPF程序不做适当处理、释放内容方面又没做到位的话,加载几张程序就会报OutOfMemery。 这时候图片切分很有必要。  WPF程序加载20张15M的图片,程序不会死、 但是一次性或多次加载300M的图片,嘿嘿,感兴趣的可以试试。后续单独发文讲述我是如何在WPF中切段加载超过几万像素、几百M大图的。

推荐加载方式:图片加载时,先设置DecodePixelWidth和 DecodePixelHeight。 比如Image的高度1920*1080。 那就先设置成192* 108.  让画面先快速加载出来, 然后再用延时的方式,加载高质量原图。 这样新界面打开时,速度会快很多,用户体验也会更佳,否则跳转界面老卡顿,很恼火的。
BitmapImage bitmap = new BitmapImage();
bitmap.DecodePixelWidth = 192;
bitmap.DecodePixelHeight = 108;
bitmap.UriSource = new Uri("");
Image.Source = bitmap;
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值