I've found what appears to be a very severe memory leak in the DataChartView component. Something related to bitmap caching or something possibly related to synchronized scrolling. Sample project here:
https://dl.dropboxusercontent.com/u/56947838/MemoryLeak.zip
It manifests when you rotate the device, and with this sample it takes 4-5 rotations before the process runs out of memory.
This is with the public CTP builds, but other builds we're using also exhibit similar problems.
I've replicated on both a real device (Samsung 4.4) and a Genymotion Android 5.x emulator.
Thank you!
Turns out that this behavior also occurs just by removing/adding the views even without an orientation change.
Hello Ben,
Thank you for your post.
I have reproduced this issue you are describing in your sample and one of my own, but I am still investigating it to see if it is an issue with the DataChartView itself. I have been speaking with my colleague, and it appears that it does have to do with an image caching process with Android, but it is strange that this only seems to happen with the DataChartView when more than one chart is synced with another. I will update this thread again when I have more information for you.
Please let me know if you have any other questions or concerns on this matter.
Sincerely,AndrewAssociate DeveloperInfragistics Inc.www.infragistics.com/support
Hi Ben,
It's possible this is not the scenario that we've seen before and it could be an interesting leak related to the sync settings. We'll look into that and see if it is a new scenario. A good way to tell is this. If you rotate the device pretty slowly (maybe try waiting 10 seconds between rotations?) does the issue still occur? If yes, this scenario probably represents some form of actual leak related to the synced charts stuff. However, if slowing the creation/destruction down avoids the scenario, then we have a different non-leak scenario.
If this is the same issue I've seen before, it isn't actually a leak, per-se, but rather an artifact of some of the more strange ways that Anrdoid deals with bitmap memory. The long and the short of it is, that when your app runs out of heap memory, the Dalvik VM forces a garbage collection to occur. Critically, though, Android bitmap classes do not release their native memory until they are processed by the finalizer queue, not when they are first collected.
This means that it is a common problem on Android that if an application uses a lot of images and you destroy and create views that contain them, you can wind up with enough partially collected images that an OutOfMemoryException can be thrown, even though none of the offending bitmaps are actually still referenced.
You can proactively destroy bitmaps with the recycle() method to avoid this.
But how does that relate to the chart? We need to use multiple layered bitmaps to render the content of the chart. If you have a device with a humongous resolution and the chart is taking up a lot of space, these bitmaps are BIG. However, the standard maximum heap allocation for an Android app is, by default, very small, so you can only have a few sets of these images in memory at a time unless you:
Note, with more recent builds (non-public) we have mitigated this issue by removing an unnecessary background layer from the component, meaning each chart takes less memory, but you may still be able to reproduce the issue if you cause views containing the chart to be created and destroyed quickly enough. This way there are more released bitmaps that haven't been finalized than the system can cope with.
The short version is that if you do either of the above bullets, we think you should be ok, since that is our experience, but definitely let us know if you can still reproduce the issue. Last time we looked into it, it definitely didn't seem like a leak. If it were leaking as bad as bad as your scenario would imply, we wouldn't be able to scroll through every chart sample in our Samples Browser without it crashing, as we do. Rather, if you have a small heap (as you do by default in Android) and are creating new views without proactively destroying the images contained in the old views you can cross a threshold where you have too many released but undestroyed images, and cross the heap limit threshold.
BTW, the reason you are able to hit this via rotating the device is that the default behavior in and android application is to destroy the layout and recreate on an orientation change. You can modify this behavior and let your app resize its views instead and that would also be a valid way to avoid this scenario.
Let me know if you have any questions about this.
-Graham
Also, note, we'll be looking whether there are other ways to make the chart more proactive about releasing its bitmap content. However, all of the avenues we thusfar tested were unsatisfactory compared to providing a method to let us be proactively notified when you were done with the chart.
Thank you for the reply.
I added calls to your DataChartView.destroy() at appropriate times (Fragment.onDestroyView() in our code) and it doesn't improve matters.
The leak is easy to spot in an instance of SyncLink. It grows every time a sync'd pair DataChartView is created. This is not an Android VM bitmap caching issue. I'm very well versed in those types of issues and I'm sympathetic, but this ain't that. Modern VM's are very good at Bitmap reclamation anyways, so that argument is not one easily made these days.
I've attached a screenshot showing a MAT trace of a heap dump that shows 35mb of retained heap after 7-8 DataChartViews are destroyed/recreated (with calls to .destroy as well).
https://dl.dropboxusercontent.com/u/56947838/Screen%20Shot%202015-03-30%20at%2012.42.53%20PM.png
The mitigation strategies you propose are, unfortunately, all non-starters for our app for a variety of reasons. They all would just cover up the leak in DataChartView however.
Thank you.