如何在WP7中实时监控内存使用量

在windows phone 7 里开发的程序在运行过程中如果内存使用超过90M程序就会自动退出,但是在模拟器上没有这个限制,因此必须有方法帮助你在调试程序的时候时刻监控内存占用,否则即使在模拟器上没问题,一旦到了真机上就可能会出问题,最近在开发中我就遇到了这个问题,经过摸索,发现phone7提供了DeviceExtendedProperties可用于取得内存使用情况。

办法一:在app.xaml.cs里加入一个timer, 设置每间隔一段时间输出内存占用值到控制台:

1.在app.xaml.cs里添加下列函数:

        void timer_Tick(object sender, EventArgs e)        
         {            //GC.GetTotalMemory(true);            
             long deviceTotalMemory = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("DeviceTotalMemory");            
             long applicationCurrentMemoryUsage = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage");            
             long applicationPeakMemoryUsage = (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage");             
             System.Diagnostics.Debug.WriteLine(DateTime.Now.ToLongTimeString());            
             System.Diagnostics.Debug.WriteLine("Device Total : " + deviceTotalMemory.ToString());           
             System.Diagnostics.Debug.WriteLine("App Current : " + applicationCurrentMemoryUsage.ToString());            
             System.Diagnostics.Debug.WriteLine("App Peak : " + applicationPeakMemoryUsage.ToString());        
         }

2。在构造函数public App{}里添加 :

            System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(1000d);
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();

 

办法二:

  使用MemoryDiagnosticsHelper.cs类,下面是源代码,将此文件添加到工程中。

然后将MemoryDiagnosticsHelper.Start(TimeSpan.FromMilliseconds(500), true); 这一句添加到构造函数public App{}里

   if (System.Diagnostics.Debugger.IsAttached)

{

...
MemoryDiagnosticsHelper.Start(TimeSpan.FromMilliseconds(500), true);

...

}

 

用模拟器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 MemoryDiagnostics
{
  
/// <summary>
  
/// Helper class for showing current memory usage
  
/// </summary>
  public static class MemoryDiagnosticsHelper
  {
    
static Popup popup;
    
static TextBlock currentMemoryBlock;
    
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<MemoryCheckpoint> recentCheckpoints;

    
static bool alreadyFailedPeak = false// to avoid endless Asserts

    
/// <summary>
    
/// Starts the memory diagnostic timer and shows the counter
    
/// </summary>
    
/// <param name="timespan">The timespan between counter updates</param>
    
/// <param name="forceGc">Whether or not to force a GC before collecting memory stats</param>
    [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<MemoryCheckpoint>();

      StartTimer(timespan);
      ShowPopup();
    }

    
/// <summary>
    
/// Stops the timer and hides the counter
    
/// </summary>
    [Conditional("DEBUG")]
    
public static void Stop()
    {
      HidePopup();
      StopTimer();
      recentCheckpoints 
= null;
    }

    
/// <summary>
    
/// Add a checkpoint to the system to help diagnose failures. Ignored in retail mode
    
/// </summary>
    
/// <param name="text">Text to describe the most recent thing that happened</param>
    [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()));
    }

    
/// <summary>
    
/// Recent checkpoints stored by the app; will always be empty in retail mode
    
/// </summary>
    public static IEnumerable<MemoryCheckpoint> RecentCheckpoints
    {
      
get
      {
        
if (recentCheckpoints == null)
          
yield break;

        
foreach (MemoryCheckpoint checkpoint in recentCheckpoints)
          
yield return checkpoint;
      }
    }

    
/// <summary>
    
/// Gets the current memory usage, in bytes. Returns zero in non-debug mode
    
/// </summary>
    
/// <returns>Current usage</returns>
    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
    }

    
/// <summary>
    
/// Gets the peak memory usage, in bytes. Returns zero in non-debug mode
    
/// </summary>
    
/// <returns>Peak memory usage</returns>
    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"] };
      currentMemoryBlock 
= new TextBlock { Text = "---", FontSize = fontSize, Foreground = foreground };
      peakMemoryBlock 
= new TextBlock { Text = "", FontSize = fontSize, Foreground = foreground, Margin = new Thickness(5000) };
      sp.Children.Add(currentMemoryBlock);
      sp.Children.Add(
new TextBlock { Text = " kb", FontSize = fontSize, Foreground = foreground });
      sp.Children.Add(peakMemoryBlock);
      sp.RenderTransform 
= new CompositeTransform { Rotation = 90, TranslateX = 480, TranslateY = 425, 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();
      currentMemoryBlock.Text 
= string.Format("{0:N}", mem / 1024);
      
int safetyBand = GetSafetyBand(mem);
      
if (safetyBand != lastSafetyBand)
      {
        currentMemoryBlock.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;
    }
  }

  
/// <summary>
  
/// Holds checkpoint information for diagnosing memory usage
  
/// </summary>
  public class MemoryCheckpoint
  {
    
/// <summary>
    
/// Creates a new instance
    
/// </summary>
    
/// <param name="text">Text for the checkpoint</param>
    
/// <param name="memoryUsage">Memory usage at the time of the checkpoint</param>
    internal MemoryCheckpoint(string text, long memoryUsage)
    {
      Text 
= text;
      MemoryUsage 
= memoryUsage;
    }

    
/// <summary>
    
/// The text associated with this checkpoint
    
/// </summary>
    public string Text { getprivate set; }

    
/// <summary>
    
/// The memory usage at the time of the checkpoint
    
/// </summary>
    public long MemoryUsage { getprivate set; }
  }
}

 

 

 

posted @ 2010-11-09 13:32  大厨无盐煮  阅读(722)  评论(2)    收藏  举报