Disclaimer!: I am not a Window Phone Expert though dabble occasionally…
The clean-up for the Windows Phone LongListSelector control on Windows Phone 8 often does not recover a relatively large amount of memory that the control has been using. Some/much of the lost memory can be recovered as shown below.
I was writing a language learning app and had a page that contained a Pivot control with half a dozen PivotItems. Most of these PivotItems contained a LongListSelector. This page was typically loaded many times during typical use of the app. Memory use was observed to rapidly grow to 150MB and more, despite only text – no images or other media – being used.
I extracted a small but representative sample of the offending code into a separate app to investigate. This can be downloaded here.
The start screen is below. The check box allows my fix/workaround to be switched on/off.
To demonstrate the issue, don’t tick the checkbox. Click start.
The next screen is a sample screen from my language app, filled with random dummy data. In my app, this screen is used often in between various other screens. To simulate this, I clicked the “Next” button 30 times (the page URL contains a dummy random parameter to ensure it reloads each time). At the end of this, the phone shows memory use has increased rapidly:
For good measure, I added a button to force a full, blocking garbage collection. This recovered a small amount of memory:
Clearly, nearly 100MB with only small amounts of text and no use of images/sound/video is quite excessive.
The memory use over the lifetime of the text was captured in the Memory Profiler:
It is worth noting that the total memory captured in the Memory Profiler was only 13MB. This can be downloaded here.
Clearly there is a large discrepancy between the 13MB total being reported in the profiler and the nearly 100MB use observed. The profiler doesn’t cover system memory, which got me thinking that something within one of the native controls could be the cause.
It is worth noting that I was already removing the page from the Back Stack and I had verified that the page was being cleaned up by putting a debug statement in the page destructor. So, although the clean-up was happening in theory, it certainly wasn’t cleaning up everything.
Workaround / Fix
After some trial and
error improvement, I found an approach that was able to recover most/all of the memory that was being lost. This involved clearing all of the values of the dependency properties on the LongListSelector controls (and the Pivot control too). A snippet of the code is given at the bottom of this post.
I am not sure if this is widely regarded as normal practice. It did not seem obvious to me.
Running the test app again, this time with the Cleanup checkbox ticked:
After the 30 pages:
After forcing a garbage collection:
Clearly, significantly better. Also reflected in the Memory Profile:
The workaround/fix makes use of the DependencyObject.ClearValue method:
The full source code can be found in the sample project. The workaround/fix is located around line 105 in PivotPage.xaml.cs
This does seem rather an ugly brute force fix and perhaps others are possible. But sometimes you just have to go with what works…