Windows Phone7 开发中的性能、内存使用监控方法

fmms 12年前

window phone7对手机硬件有对应要求,其中一项是手机内存不低于256M,这对运行在手机上的应用也带来了限制,那就是资源分配;所以在开发过程中关注自己 应用的资源使用情况是非常有必要的,如果应用占用资源过多,在提交marketplace时,提交审核过程可能会被拒绝,那么就这里就分享下,内存实时监 控的方法了。

原理是使用 DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage")获取应用使用 的内存,然后启用一个timer定时查询并显示到ui上,为了不影响应用在正常情况下的使用,只有在debug时将内存使用情况显示出来,这样可以看到在 各个页面上运行时内存使用情况,可以分析内存消耗在具体哪个地方;

代码如下:

using System;  using System.Net;  using System.Windows;  using System.Windows.Controls;  using System.Windows.Documents;  using System.Windows.Ink;  using System.Windows.Input;  using System.Windows.Media;  using System.Windows.Media.Animation;  using System.Windows.Shapes;  using System.Windows.Controls.Primitives;  using System.Windows.Threading;  using Microsoft.Phone.Info;  using System.Diagnostics;  using System.Collections.Generic;  namespace ScrollViewerStyle  {      public class MemoryDiagnostics      {        }      ///      /// Helper class for showing current memory usage      ///      public static class MemoryDiagnosticsHelper      {          static Popup popup;          static TextBlock currentMemoryKB;          static TextBlock currentMemoryMB;          static TextBlock peakMemoryBlock;          static DispatcherTimer timer;          static bool forceGc;          const long MAX_MEMORY = 90 * 1024 * 1024; // 90MB, per marketplace          static int lastSafetyBand = -1; // to avoid needless changes of colour            const long MAX_CHECKPOINTS = 10; // adjust as needed          static Queue recentCheckpoints;            static bool alreadyFailedPeak = false; // to avoid endless Asserts            ///          /// Starts the memory diagnostic timer and shows the counter          ///          /// The timespan between counter updates          /// Whether or not to force a GC before collecting memory stats          [Conditional("DEBUG")]          public static void Start(TimeSpan timespan, bool forceGc)          {              if (timer != null) throw new InvalidOperationException("Diagnostics already running");                MemoryDiagnosticsHelper.forceGc = forceGc;              recentCheckpoints = new Queue();                StartTimer(timespan);              ShowPopup();          }            ///          /// Stops the timer and hides the counter          ///          [Conditional("DEBUG")]          public static void Stop()          {              HidePopup();              StopTimer();              recentCheckpoints = null;          }            ///          /// Add a checkpoint to the system to help diagnose failures. Ignored in retail mode          ///          /// Text to describe the most recent thing that happened          [Conditional("DEBUG")]          public static void Checkpoint(string text)          {              if (recentCheckpoints == null) return;              if (recentCheckpoints.Count >= MAX_CHECKPOINTS - 1) recentCheckpoints.Dequeue();              recentCheckpoints.Enqueue(new MemoryCheckpoint(text, GetCurrentMemoryUsage()));          }            ///          /// Recent checkpoints stored by the app; will always be empty in retail mode          ///          public static IEnumerable RecentCheckpoints          {              get              {                  if (recentCheckpoints == null) yield break;                    foreach (MemoryCheckpoint checkpoint in recentCheckpoints) yield return checkpoint;              }          }            ///          /// Gets the current memory usage, in bytes. Returns zero in non-debug mode          ///          /// Current usage         public static long GetCurrentMemoryUsage()          {  #if DEBUG              // don't use DeviceExtendedProperties for release builds (requires a capability)              return (long)DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage");  #else        return 0;  #endif          }            ///          /// Gets the peak memory usage, in bytes. Returns zero in non-debug mode          ///          /// Peak memory usage         public static long GetPeakMemoryUsage()          {  #if DEBUG              // don't use DeviceExtendedProperties for release builds (requires a capability)              return (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage");  #else        return 0;  #endif          }            private static void ShowPopup()          {              popup = new Popup();              double fontSize = (double)Application.Current.Resources["PhoneFontSizeSmall"] - 2;              Brush foreground = (Brush)Application.Current.Resources["PhoneForegroundBrush"];              StackPanel sp = new StackPanel { Orientation = Orientation.Horizontal, Background = (Brush)Application.Current.Resources["PhoneSemitransparentBrush"] };              currentMemoryKB = new TextBlock { Text = "---", FontSize = fontSize, Foreground = foreground };              peakMemoryBlock = new TextBlock { Text = "", FontSize = fontSize, Foreground = foreground, Margin = new Thickness(5, 0, 0, 0) };              sp.Children.Add(currentMemoryKB);              //sp.Children.Add(new TextBlock { Text = " kb", FontSize = fontSize, Foreground = foreground });              sp.Children.Add(peakMemoryBlock);                currentMemoryMB = new TextBlock { Text = "---", FontSize = fontSize, Foreground = foreground };              sp.Children.Add(currentMemoryMB);                sp.RenderTransform = new CompositeTransform { Rotation = 90, TranslateX = 480, TranslateY = 480, CenterX = 0, CenterY = 0 };              popup.Child = sp;              popup.IsOpen = true;          }            private static void StartTimer(TimeSpan timespan)          {              timer = new DispatcherTimer();              timer.Interval = timespan;              timer.Tick += new EventHandler(timer_Tick);              timer.Start();          }            static void timer_Tick(object sender, EventArgs e)          {              if (forceGc) GC.Collect();                UpdateCurrentMemoryUsage();              UpdatePeakMemoryUsage();          }            private static void UpdatePeakMemoryUsage()          {              if (alreadyFailedPeak) return;                long peak = GetPeakMemoryUsage();              if (peak >= MAX_MEMORY)              {                  alreadyFailedPeak = true;                  Checkpoint("*MEMORY USAGE FAIL*");                  peakMemoryBlock.Text = "FAIL!";                  peakMemoryBlock.Foreground = new SolidColorBrush(Colors.Red);                  if (Debugger.IsAttached) Debug.Assert(false, "Peak memory condition violated");              }          }            private static void UpdateCurrentMemoryUsage()          {              long mem = GetCurrentMemoryUsage();              currentMemoryKB.Text = string.Format("{0:N}", mem / 1024) + "KB  ";              currentMemoryMB.Text = string.Format("{0:f}", mem / 1024.00 / 1024.00) + "MB";              int safetyBand = GetSafetyBand(mem);              if (safetyBand != lastSafetyBand)              {                  currentMemoryKB.Foreground = GetBrushForSafetyBand(safetyBand);                  lastSafetyBand = safetyBand;              }          }            private static Brush GetBrushForSafetyBand(int safetyBand)          {              switch (safetyBand)              {                  case 0:                      return new SolidColorBrush(Colors.Green);                    case 1:                      return new SolidColorBrush(Colors.Orange);                    default:                      return new SolidColorBrush(Colors.Red);              }          }            private static int GetSafetyBand(long mem)          {              double percent = (double)mem / (double)MAX_MEMORY;              if (percent <= 0.75) return 0;                if (percent <= 0.90) return 1;                return 2;          }            private static void StopTimer()          {              timer.Stop();              timer = null;          }            private static void HidePopup()          {              popup.IsOpen = false;              popup = null;          }      }        ///      /// Holds checkpoint information for diagnosing memory usage      ///      public class MemoryCheckpoint      {          ///          /// Creates a new instance          ///          /// Text for the checkpoint          /// Memory usage at the time of the checkpoint          internal MemoryCheckpoint(string text, long memoryUsage)          {              Text = text;              MemoryUsage = memoryUsage;          }            ///          /// The text associated with this checkpoint          ///          public string Text { get; private set; }            ///          /// The memory usage at the time of the checkpoint          ///          public long MemoryUsage { get; private set; }      }  }
当然要想使用还得在app.xaml.cs构造函数里启用监控
///          /// Constructor for the Application object.          ///          public App()          {              // Global handler for uncaught exceptions.               UnhandledException += Application_UnhandledException;                // Standard Silverlight initialization              InitializeComponent();                // Phone-specific initialization              InitializePhoneApplication();                // Show graphics profiling information while debugging.              if (System.Diagnostics.Debugger.IsAttached)              {                  // Display the current frame rate counters.                  Application.Current.Host.Settings.EnableFrameRateCounter = true;                    // Show the areas of the app that are being redrawn in each frame.                  //Application.Current.Host.Settings.EnableRedrawRegions = true;                    // Enable non-production analysis visualization mode,                   // which shows areas of a page that are handed off to GPU with a colored overlay.                  //Application.Current.Host.Settings.EnableCacheVisualization = true;                    // Disable the application idle detection by setting the UserIdleDetectionMode property of the                  // application's PhoneApplicationService object to Disabled.                  // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run                  // and consume battery power when the user is not using the phone.                  PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;                  //启动性能监控,只在debug时候                  MemoryDiagnosticsHelper.Start(TimeSpan.FromMilliseconds(500), true);              }          }

运行效果:

Windows Phone7 开发中的性能、内存使用监控方法

转自:http://www.cnblogs.com/yoainet/archive/2012/03/01/2375775.html