Windows Phone 内存检测方法

 

      在 VS 的开发环境中,有内存性能分析的工具(VS 的菜单栏——> 调试——> 启动 Windows Phone性能分析)

可以分析应用的内存占用情况,但是通常只有在程序停止运行结束后,我们才能看到数据。但是有时候我们想在程序

运行过程中时事看到内存占用情况,比如在执行某个特定的方法后获取内存信息。这里我写了一个简单的方法,在程序

运行时,每隔四秒就把内存信息打印到屏幕上,为了在应用的所有页面都可以检查,我们使用之前写过的一个自定义 Toast

输出框(文章和代码工程)。

   

      首先在页面的构造函数中,初始化一个 计时器:

            // 初始化计时器,每隔四秒钟就打印当前应用所占内存、峰值、和设备总内存
            dispacherTimer = new System.Windows.Threading.DispatcherTimer();
            dispacherTimer.Interval = TimeSpan.FromSeconds(4);
            dispacherTimer.Tick += new EventHandler(dispacherTimer_Tick);

定义定时器调用的方法:

        #region 内存使用情况
        static string total = "DeviceTotalMemory";
        static string current = "ApplicationCurrentMemoryUsage";
        static string peak = "ApplicationPeakMemoryUsage";

        static long totlaBytes;
        static long currentBytes;
        static long peakBytes;

        static System.Windows.Threading.DispatcherTimer dispacherTimer;
       
        void dispacherTimer_Tick(object sender, EventArgs e)
        {
            // 获取设备的总内存
            totlaBytes = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue(total);

            // 获取应用当前占用内存
            currentBytes = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue(current);

            // 获取内存占用的峰值
            peakBytes = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue(peak);
            
            // 使用自定义的 MyDialog 控件打印出来
            MyDialog.ShowToastMessage(string.Format("当前:{0:F2}MB;  峰值:{1:F2}MB;  总:{2:F2}MB;", currentBytes / (1024 * 1024.0), peakBytes / (1024 * 1024.0), totlaBytes / (1024 * 1024.0)));
        }
        #endregion

 

在xaml 页面中添加两个按钮,分别用来启动和关闭内存信息检测,相应的 C# 函数:

        // 取消内存信息打印,释放资源
        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            dispacherTimer.Stop();
            dispacherTimer.Tick -= new EventHandler(dispacherTimer_Tick);
            dispacherTimer = null;
        }

        // 开始向屏幕输出内存情况
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            if (dispacherTimer != null)
            {
                dispacherTimer.Start();
            }
        }

 

显示截图:

 

    内存占用的问题在 WP 的开发中是比较棘手的。因为市面上的 Lumia系列的手机,很多都是一体机,无论是

800 还是 920,它们在运行应用时,如果你的应用持续占用超过 120MB 的内存,那么它的发热情况是非常明显

的。而且导致发热的问题主要是内存的问题,并非 CPU 消耗的问题,而且在传统的 Silverlight 应用中,相对于

游戏应用,使用的数学运算等等消耗 CPU 的资源往往是微不足道的。

    我在开发过程中,总结了内存占用的一些情况,其中最主要的是在页面中绘制的元素太多,或者页面的显示尺寸太

大,比如在一个 ListBox 中显示新闻,屏幕的高度是 800px,每屏显示 4条新闻,如果当前 ListBox 中共有24 条新闻,

那么该 ListBox 就是 6 屏 X 800px = 4800 px  的高度 !!!如果这 24条全部显示在页面中,内存占用是 60MB,

但是用户看到的有效信息只是屏幕中显示的 4条。所以把 ListBox 换成 LongListSelector (支持虚拟化和内存复用)

是很有必要的。如果想继续使用 ListBox 可以写一个算法(曾经写过),就是ListBox 只显示当前四条的新闻,其它

20条的新闻可以把它们的 Visibility 设置为 System.Windows.Visibility.Collapsed,当用户的手指划到那条新闻时,

再把那条新闻的该属性设置为  System.Windows.Visibility.Visible, 这样如果全部显示 24条新闻占用 60MB,那么

通过这个算法,内存只需要 25MB 左右。

      通常导致内存增加,可能是程序中一些不再使用的对象得不到有效的释放,这些对象越来越多,从而导致内存泄露,

可能的原因:

1)静态对象的引用

2)事件没有与方法解除订阅

3)静态事件没有与方法解除订阅

4)非托管资源(实现了 IDispose 接口),没有调用 Dispose 方法

5)非托管资源的 Dispose 方法没有执行完成

      另一个问题是,有的开发者在开放 WP8 的过程中,担心使用 async 和 await 关键字过多,会不会导致系统频繁创建

额外的线程过多,结果消耗很多系统资源。其实并非如此,因为在 .net 4.5 中引入的 async 和 await 关键字只是简化了

.net 4.0 中 Task 的创建和维护,通过使用同步编程的方式实现了异步线程的调用,并且 Task 在异步调用时,底层并非

创建了新的线程,而是使用的线程池技术,达到线程复用的目的。所以在 WP8 的开发中,尽可能的使用 async 和 await

因为它们不会增加应用过多占用系统的资源。

      最后还有一点建议,就是在程序开发的时候,比如在应用中需要显示网页内容,一个选择是在应用中放一个 WebBrowser

控件,除非迫不得已,否则尽可能调用  Microsoft.Phone.Tasks.WebBrowserTask, 从而使用系统的 IE 浏览器打开网页内容

,因为 WebBrowser 控件显示网页内容时,所占用的内存也是相当大的,而且使用 IE 打开网页内容,不但系统会优化系统

资源,而且它所占用的内存并不会算入到应用占用的内存中去。

        同理,相对于调用摄像头的 API(高级捕获 PhotoCaptureDevice 和 PhotoCamera ),最好使用系统任务:

Microsoft.Phone.Tasks.CameraCaptureTask。

posted @ 2013-05-28 09:21  博琼  阅读(639)  评论(1编辑  收藏  举报