【续】WPF支持GIF的各种方法

前一篇介绍了我的GifImage与其他人的GIF支持实现,以及对比;这一篇再进行另一项对比。


本文主要是自我记录,对读者的意义可能不大。在前文的基础上,我修改了GifImage,使其支持从两种来源获得gif图像。一是URI,二是Stream。另外,我还对GifImage进行了优化,做了很多测试保证反复创建GifImage,内存不会暴增。(事实上可以保持稳定)

因为GifImage内部使用了(有)timer,timer事件中有一项事件处理函数是GifImage里的一个方法。所以两者循环依赖,导致都不能被垃圾回收器回收,导致内存不能释放。

解决方法是显式销毁timer。比如GifImage实现IDisposable接口,在Dispose方法里取消订阅timer事件(,并设置timer=null,非必要)。要理解显式销毁的含义,就是比如说创建了GifImage,加入到WPF的StackPanel里,不用了的时候要stackPanel.Chilhren[i].Dispose(),再Clear()。

这里学到的是,不仅仅当类字段中有IDisposable成员(FxCop能检查此情况),或有非托管资源时,该类需要实现IDisposable接口;当类订阅了别人的事件时,也应该实现IDisposable接口。另外,推荐大家读一读Stephen Cleary的文章《IDisposable: What Your Mother Never Told You About Resource Deallocation》。他列举了IDisposable的坏处,反对微软的Dispose模式(即Dispose调用虚方法Dispose(bool disposing)),然后自己提出个用来实现IDisposable接口的更好的方案——我觉得他的方案更简洁更易于理解。

话说回来,刚才说GifImage有两个属性UriSource和StreamSource,分别从指定的Uri或Stream获得GIF图像。这么设定是因为在我的程序里,同一GIF图像会在多处显示,这样的话用同一个StreamSource赋值可能——所以需要试验——会减少内存占用。

与此相关的一点是BitmapCacheOption枚举,解析GIF时需要用到,它可能会影响性能。我本来想一份Stream,多个GifImage使用;试想如果那份Stream又被各个GifImage缓存起来了,那内存不是根本没有节省?还不如用UriSource呢!——所以也需要试验。

试验设计

获得GIF图片的途径有两种,URI和Stream;缓存方式有三种,OnDemand、OnLoad和None。所以2×3=6,共进行6次试验。试验结果输出到控制台,利用cmd重定向命令可以写入文本文件,再导入电子表格,统计、绘图。

测量工具

测CPU占用率,用的经我改造的Ben Watson的CpuUsage类

测私有内存和工作集,用的是PerformanceCounter。

读者可能问为什么测CPU不用PerformanceCouter。因为在我的电脑上,cpuCouter = new PerformanceCouter("Process", "% Processor Time", process.ProcessName),然后GetValue()行为怪异。往往取出的值都是0,而明显Process Explorer显示的值不是0;有时又爆高。

读者可能问为什么测私有内存和工作集不用Process.WorkingSet64之类的。它们确实能给出值,但经过多次试验,还是PerformanceCouter给出的值比较接近Process Explorer。(我不是说Process Explorer的值是绝对准确的。)


具体过程不述,直接看结果。




可以发现useUri=false的,普遍内存占用比较低。然后useUri=true中,不同的CacheOption对内存占用的影响看不太出来,于是再计算其他指标。


测试配置 useUri=False; CacheOption=OnDemand
  CPU 私有内存 工作集 Collected
平均 55 70738 67199


72460 68428
         
方差 7.45 2,910,746 3,208,384  


测试配置 useUri=False; CacheOption=OnLoad
  CPU 私有内存 工作集 Collected
平均 55 70861 66626


71392 67764 4860
         
方差 9.34 3,464,841 7,504,836  

测试配置 useUri=False; CacheOption=None
  CPU 私有内存 工作集 Collected
平均 55 70713 67573


70744 68384 4860
         
方差 10.44 3,086,858 4,010,879  

这就明显了,CacheOption=OnDemand的,cpu、私有内存、工作集占用最稳定,平均值也较小。


所以,当同一GIF图片要在WPF里的多处显示时,应当用StreamSource,且CacheOption=OnDemand。CacheOption.Default目前等于CacheOption.OnDemand。


爱让一切都对了

2012年1月26日

阅读更多
换一批

没有更多推荐了,返回首页