如何在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( 5 0 0 0 ) };
      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 {  get private   set ; }

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

 

 

 

你可能感兴趣的:(wp7)