window phone7开发中的性能、内存使用监控方法
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
{
}
/// <summary>
/// helper class for showing current memory usage
/// </summary>
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<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"] };
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;
}
}
/// <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; }
}
}
当然要想使用还得在app.xaml.cs构造函数里启用监控
/// <summary>
/// constructor for the application object.
/// </summary>
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);
}
}
运行效果:
实例下载:
摘自 johnny默默
上一篇: ios多线程之NSThread使用技巧
下一篇: 抖音营销怎么做?这9个技巧告诉你