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!
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.
Graham/Andrew - Thank you for your work on this issue. I am working with Ben on this project. We are cloning an iOS application that heavily uses NucliOS. The stability of the Android charting components is extremely important to us and our clients. We trust this is a high priority for your team and a fix can be found soon.
Hello Ben/Caylan,
Thank you for your response.
I have asked our engineering staff to examine this issue further. To ensure that this issue will receive attention, I have logged this behavior in our internal tracking system with a development ID of 192038.
I have made the case that is attached to this forum thread visible to Ben, so that you can track the progress of this development issue. The case number is CAS-153410-S1P3C6 and you can access it at https://ko.infragistics.com/my-account/support-activity.
Please let me know if you have any other questions or concerns on this matter.
Sincerely,AndrewAssociate DeveloperInfragistics Inc.www.infragistics.com/support
Hey,
Yeah, as I said, this could be a different scenario than what we have run into before. Everything I said still applies though.
Presumably the sync channel is left up and destroy doesn't take it down.
In the interim. For android you can achieve most of what sync channel gives you by alternatively listening for
setOnActualWindowRectChanged...
And then calling setWindowRect on the other chart, and vice versa. You would need an extra boolean, though, to make sure you aren't bouncing the value back and forth ad infinitum though. I'm sure Andrew could help you set that up if that doesn't make sense. Hopefully we can have this resolved soon though, and you could request an untested build if necessary.
Thanks for the additional info.