前一篇介绍了我的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次试验。试验结果输出到控制台,利用cm