WPF/Silverlight深度解决方案:(八)誓将内存释放到底

WPF/Silverlight应用程序长时间运行后会产生非常多的内存垃圾(内存泄露例外),特别是在经常需要进行Remove操作的粒子、动画、游戏等方面的应用,国外高手们提出的方案我归纳了一下主要有:

1)  UIElement控件实例= null

2)  定时调用GC.Collect()

3)  让控件继承Idisposable接口,并实现相应逻辑

这三种方法都有一定的作用,但是实际使用中均往往难以达到预期效果。特别是在Silverlight应用中,目前的Flash/Flex制作的RPG网页游戏都有一个通病:内存不断增加导致运行二、三十分钟后浏览器即进入假死状态,Silverlight如果无法处理好内存的释放,命运或许终究一样。

那么我们是否还有其他更好的方法实现内存垃圾的释放?大家不妨做这么一个测试,以IE浏览器为例,当我们打开一个运行有Silverlight应用程序的页面后,记录下任务管理器中该IEXPLORE.EXE的内存使用量,然后运行一段时间,再记录此时的内存使用量,最后将该页面最小化再还原回来,大家将看到该IEXPLORE.EXE的内存使用量已被完全的释放干净,如同新开的网页一般。这老掉牙的东西已算不上什么技巧,但是却给了我们一条内存彻底释放的思路:既然Silverlight应用程序是镶嵌在网页中的,我们能否通过该方法去释放内存呢?答案是肯定的。

以我的Silverlight游戏引擎Demo为例,刚加载完时内存使用约56M

然后我刷了80个怪,并将它们全部消灭干净后内存使用量约为132M

接着将此页面最小化再还原,内存瞬间释放到约20M

并且在不刷出新怪的前提下,我环绕整个地图走完每个角落后,内存最大时不超过56M,从而证明了IE最小化后将瞬间释放完Silverlight内存垃圾的观点是正确的。至于例如FireFox浏览器如何最小化时释放内存大家可以参考:让火狐浏览器最小化时释放内存这篇文章。

很多朋友或许要说了:这些都是废话嘛,连蚂蚁都知道。难不成我还要在Silverlight页面上放个注释:客户们注意啦~为了您和浏览器的健康,请定时最小化浏览器。

其实我想和大家说的,这仅仅是一条思路。大家不妨想想,其实我们是完全可以将这种方法无缝的嵌入到页面中去的。

Winform/WPF中,实现该方法仅仅只需通过下面一段代码即可实现模拟释放内存(原文地址)

     [DllImport("kernel32.dll")]

     public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);

     public void FlushMemory() {

         GC.Collect();

         GC.WaitForPendingFinalizers();

         if (Environment.OSVersion.Platform == PlatformID.Win32NT) {

             SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);

         }

     }

      但是WindowsAPI无法在Silverlight中使用,我们该怎么办呢?

再看下面这段代码:
我们可以使用一个JssetInterval方法每间隔一段时间去自动释放内存,该方法原理为将浏览器最小化后再找回焦点,我们肉眼看到仅是页面闪了一下,再无任何其他感觉。就这么一瞬间,就算Silverlight应用程序导致浏览器占用了数百M的内存,照样完全释放无误。这是该例子Demo,有兴趣的朋友可以下载体验一下。

<script type="text/javascript">

    function intervalFlushMemory() {

        setInterval(FlushMemory, 60000);

    }

    function FlushMemory() {

        min.Click();

        window.focus();

    }

</script>

<body onload="intervalFlushMemory();">

    ……

<object id="min"

type="data:application/x-oleobject" classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11">

        <param name="Command" value="Minimize" />

    </object>

<button onclick="FlushMemory();">释放内存</button>

……

</body>

 

非常不幸的是,通过<object>实现内存释放的方法目前只能在IE中使用,而且由于诸多限制还无法很好的广泛使用,解决的最终方法目前我只想到两个:

1)  能否有相关的SilverlightAPI直接实现类似功能,或者后台代码C#中去实现呢?

2)  通过将该<object>制作成控件并打包成cab,并加上数字签名,以ActiveX的形式让用户使用,实在是够麻烦的

文章要结尾了,但是我无法兴奋起来,C++开发者的冷眼嘲笑让我始终有种沉痛的感觉:Silverlight的内存垃圾本是可以轻松释放的,为何MS就不能让我们畅快一点?托管是否能更绅士些?

最后,我想告诉大家的是,本文的目的并没有真正达到,因为这所有的方法都不是完美的解决方案,作为一些思路,我希望大家能给予我更多的指点,欢迎大家留言参与Silverlight内存的相关讨论,因为我们的最终目的只有一个:誓将内存释放到底!

Silverlight还是个孩子,它的路还有很长要走;但我一直坚信:明天会更好。

作者:深蓝色右手
本系列目录及源码下载:点击进入
本文版权归作者和CSDN共有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面显著位置给出原文连接,否则保留追究法律责任的权利。

posted on 2009-10-01 01:08  哼哼唧唧  阅读(132)  评论(0编辑  收藏  举报

导航