OutOfMemoryException and where to find it
Whenever you launch your application (or process to be exact) Android allocates some of heap memory available for you device to it. It is usually a pretty small amount of memory, some 10 megabytes most probably. As soon as your application requires more memory for its objects it requests more heap size. However if your application requests more memory that is assignable to one process on your device you encounter a problem.
OutOfMemoryException is thrown and your app crashes. There are two common causes of such situation:
1) If it happens after some time in your application, after navigating through many screens or showing a lot of data several times over it is usually a memory leak. Debugging and fighting those is a topic for another time and I will write a post about it.
2) Second, less common issue is a large, fast spike in the memory allocation that makes it hard for the OS to react quickly enough and free sufficient memory for the app not to crash. This is the one I experienced.
The kind of memory allocation problem I described is not that hard to debug because more often than not it comes down to a misuse of assets. The particular problem I faced crashed the app only on certain devices and only in one place in the application. It crashed while entering MiddleParty Fragment. I realised I made several mistakes with the backgrounds of the fullscreen dialogs of MiddleParty info.
Using Android Monitor I discovered the exact place, where memory allocation happened really quick and managed to narrow it down to several factors:
– Assets not resized for every screen densities -> always loading the full-sized .png into RAM
– Picasso didn’t call .fit() so it didn’t resize the assets on its own.
– All the backgrounds being loaded in the begining instead of only when needed.
All these issues added up to the app crashing under some conditions.
The fix was quick and the bug was patched up on the Google Play some 25 minutes later. I properly down-scaled the assets so that much less memory was required for every .png file. I also called .fit() on Picasso so that the properly resized assets were cached and so it was faster to launch in the future. I also delegated the loading of fullscreen backgrounds to another Thread which made the app more responsive in those situations.