Windows Phone7 开发中的性能、内存使用监控方法
fmms
13年前
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 { } ///当然要想使用还得在app.xaml.cs构造函数里启用监控/// 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 QueuerecentCheckpoints; 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 IEnumerableRecentCheckpoints { 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; } } }
////// 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); } }
运行效果:
转自:http://www.cnblogs.com/yoainet/archive/2012/03/01/2375775.html