It is said that “A point of view is worth 80 IQ points”; the meaning perhaps being that if we can look at things in different ways then we might understand them better. The Memory Profiler that ships with the Windows Phone SDK 7.1 provides, in its own way, multiple views into the memory usage of your application, and in an earlier post we had seen how specific views helped us understand one particular issue with the application better. But even before we got to the specific views, there was a graph and a couple of rows of markers, remember? Let us discuss them briefly.
How do you even know that you need to run your application scenario through the Memory Profiler, especially since there might not be any obvious visual cue? The answer lies in an Execution Profiler warning message. The expectation is that you would run your application scenario through the Execution Profiler for evaluating visual and code performance, and if it suspects any memory related issues it will raise a warning message suggesting running the scenario through the Memory Profiler!
Users of the Execution Profiler will find the interaction model of the Memory Profiler familiar. It launches from the same page, with the difference being that you select the Memory (managed object allocations and texture usage) option. The Advanced Settings option can be ignored for the purpose of this discussion. The following is the launch page for the Memory Profiler:
A warning message is issued if the deployment target happens to be the Windows Phone Emulator. The emulator runs on the desktop, and the desktop has a different hardware architecture than the device, with different performance characteristics across the board. The warning therefore alerts you to this lack of performance fidelity. If you are doing Execution profiling beware! The emulator is still a suitable target for doing memory profiling since in that case we are dealing with (memory) allocation profiling. Clicking on the Launch Application link deploys the application to the target and commences the profiling session.
There are two ways to gracefully end the profiling session:
If the connection from Visual Studio to the target is broken for any reason (for example, if the emulator instance is closed, or the device is untethered, or the device shuts down, the connection is broken) the session is aborted.
Once the session is gracefully ended, the data gathered during the run is processed and presented graphically for analyses, starting with a Memory Usage graph plotting memory usage over time, and two rows of markers indicating image loads and GC runs as shown below:
The memory usage reported is that of private bytes: exclusive bytes allocated by the process being profiled. Some variance in memory usage is normal and not indicative of a problem. However, memory usage that keeps rising bears examination.
A tooltip on the image load marker indicates the encoding format, the ID of the executing thread on which it got loaded, the point in time when it was loaded, and how long it took to load. A spike in memory usage corresponding to an image load marker might indicate a large sized image being loaded (larger than 2000 x 2000 pixels). Windows Phone imposes this limit, and larger images will be sampled at a lower resolution, and will take longer to load. If you must use large images consider displaying only a portion that meets this limit by loading the image into a System.Windows.Media.Imaging.WriteableBitmap and using the LoadJpeg(WriteableBitmap, Stream) extension method as shown below:
int width = (int) this.image1.Width; int height = (int) this.image1.Height; Uri uri = new System.Uri("image.jpg", UriKind.Relative); StreamResourceInfo sri = Application.GetResourceStream(uri); WriteableBitmap wb = new WriteableBitmap(width, height); System.Windows.Media.Imaging.Extensions.LoadJpeg(wb, sri.Stream); this.image1.Source = wb;
The ID of the executing thread can be used to check if the image load computation is happening on the UI thread (the UI thread’s ID can be got from the CPU Usage analysis from the earlier Execution Profiling session). To keep the UI responsive it is essential to keep the UI thread relatively free, and if you notice that the image load computation is indeed happening on the UI thread, consider moving it to a background thread using the BackgroundCreation option. From XAML, this can be done as shown below:
<Image Name="image1"> <Image.Source> <BitmapImage UriSource="image.jpg" CreateOptions="BackgroundCreation"/> </Image.Source> </Image>
An exercise to try out at this point it to memory-profile an application that loads in a large image; do you see a spike in memory usage corresponding to the image load marker? What was the duration of the image load? On what thread was it getting loaded? Try using the BackgroundCreation option; now what was the thread on which the image got loaded? Did the duration of the image load change? Let us know your experience.
Memory is a limited resource on the phone, and although you are programming in a managed environment where the GC takes care of collecting unused memory you still wield control over allocation and referencing, and must monitor them to trim working set. The GC mediates all allocation requests from your code, and operates on a heap that it has partitioned into 2 regions (generations), with allocations happen in the ephemeral “Gen0” region and objects surviving a GC collection possibly promoted to an older “Gen1” region. The GC markers correspond to collections and a tooltip indicates it’s kind ("ephemeral", "Full"), the point in time when it started, and how long it took to run. An “ephemeral” GC collects only from Gen0 while a “Full” GC collects from both Gen0 and Gen1. Furthermore a “Full” GC can do a “compaction” of the heap if it happens to be significantly fragmented, and even go on to empty the system’s cache of JIT compiled code.
A GC is triggered using several heuristics:
The GC’s decision of deeming a threshold “significant” is based on internal heuristics and mentioned here for informational purposes only. The point to note though is that a “Full” GC is much more performance intensive than an “ephemeral” GC.
Armed with the graph, the markers and your own intuition, you can now get some insight into your scenario’s appetite for memory:
An exercise to try out at this point it to profile an application that has various memory allocations patterns; can you correlate the graph and markers with your own intuition? Let us know your experience.
The graph and markers provide basic information about your application’s memory usage and when combined with your own intuition of the application scenario, be used to infer several characteristics. Further drill down through the various Views can then be used to understand these characteristics better.
Would you like to know more about the Views? Let us know.
Thanks a lot!
This really helps to understand the performance tools and how to program better apps
The coding formats baked into the new Visual Studios 11 are the key to many developer’s platforms and strengths.
With a software source so compact with all these goodies, and not to mention the predefined filters in place to check the integrity of pre-written code is awesome.
I don’t write from scratch code, but rather copy and paste with a little add on here and there to try my hand from time to time.
I must admit though the detail in your blog really sheds light on the video walkthrough of Visual Studio 11 performed by Antoine Leblond -at last year’s Windows 8 Build conference.
Thanks again for your insight, I will be using 11 to see what I can do in terms of the Windows Phone app area.
- Stay Powered by Windows