










public static class MemoryDiagnosticsHelper { public static bool isStart = false; static Popup popup; static TextBlock currentMemoryKB; static TextBlock currentMemoryMB; static TextBlock currentLumitMemoryMB; 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) { isStart = true; 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() { isStart = false; 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() { // don't use DeviceExtendedProperties for release builds (requires a capability) return (long)DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage"); } /// <summary> /// Gets the current memory usage, in bytes. Returns zero in non-debug mode /// </summary> /// <returns>Current usage</returns> public static long GetCurrentPeakMemoryUsage() { // don't use DeviceExtendedProperties for release builds (requires a capability) return (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage"); } /// <summary> /// Gets the peak memory usage, in bytes. Returns zero in non-debug mode /// </summary> /// <returns>Peak memory usage</returns> public static long GetPeakMemoryUsage() { // don't use DeviceExtendedProperties for release builds (requires a capability) return (long)DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage"); } /// <summary> /// Gets the peak memory usage, in bytes. Returns zero in non-debug mode /// </summary> /// <returns>Peak memory usage</returns> public static long GetLumitMemoryUsage() { // don't use DeviceExtendedProperties for release builds (requires a capability) return (long)DeviceExtendedProperties.GetValue("ApplicationWorkingSetLimit"); } 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 = new SolidColorBrush(Colors.Red)}; //peakMemoryBlock = new TextBlock { Text = "", FontSize = fontSize, Foreground = new SolidColorBrush(Colors.White), Margin = new Thickness(5, 0, 0, 0) }; //sp.Children.Add(new TextBlock { Text = " kb", FontSize = fontSize, Foreground = foreground }); //sp.Children.Add(currentMemoryKB); currentMemoryMB = new TextBlock { Text = "---", FontSize = fontSize, Foreground = new SolidColorBrush(Colors.White) }; currentMemoryKB = new TextBlock { Text = "---", Margin = new Thickness(10, 0, 0, 0), FontSize = fontSize, Foreground = new SolidColorBrush(Colors.Red) }; currentLumitMemoryMB = new TextBlock { Text = "---", Margin = new Thickness(10, 0, 0, 0), FontSize = fontSize, Foreground = new SolidColorBrush(Colors.Green) }; sp.Children.Add(currentMemoryMB); sp.Children.Add(currentMemoryKB); sp.Children.Add(currentLumitMemoryMB); sp.RenderTransform = new CompositeTransform { Rotation = 0, TranslateX = 150, TranslateY = 0, 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*"); // if (Debugger.IsAttached) Debug.Assert(false, "Peak memory condition violated"); //} } private static void UpdateCurrentMemoryUsage() { try { long mem = GetCurrentMemoryUsage(); long feng = GetCurrentPeakMemoryUsage(); long lumit = GetLumitMemoryUsage(); currentMemoryKB.Text = string.Format("{0:f}", feng / 1024.0 / 1024.0) + "MB"; currentMemoryMB.Text = string.Format("{0:f}", mem / 1024.0 / 1024.0) + "MB"; currentLumitMemoryMB.Text = string.Format("{0:f}", lumit / 1024.0 / 1024.0) + "MB"; } catch { } //int safetyBand = GetSafetyBand(mem); //if (safetyBand != lastSafetyBand) //{ // currentMemoryKB.Foreground = GetBrushForSafetyBand(safetyBand); // lastSafetyBand = safetyBand; //} } private static Brush GetBrushForSafetyBand(int safetyBand) { return new SolidColorBrush(Colors.Red); //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; } }
调用方式:
MemoryDiagnosticsHelper.Start(TimeSpan.FromMilliseconds(500), true);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。