In my previous article, I have mentioned that I am doing memory analysis for one of our apps. While investigating memory usage on Motorola Nexus 6 phone, I realized something unusual.
Android Studio’s Memory Monitor was telling me that our app was using 68 MB memory. The app doesn’t have any large images except the one in the background. I decided to investigate the reason behind it and I finally fixed the issue. In this article, will explain how I tracked down and fixed the issue.
To start with, I used Allocation Tracker of Android Studio’s Memory Monitor. I expanded Thread 1 saw that onCreate() was making an allocation of 49,035,328 bytes (~47 MB). I expanded the call until I find the cause. Looking at the calls, it is obvious that an image is causing this issue.
I put break points to onCreate() and stepped into the calls until I reach PhoneWindow.java class. In this class, background image is assigned in this block of code:
The background Bitmap had a resolution of 2626×4669. However, the background image I used has a resolution of 750×1334.
1) The reason Bitmap is scaled to 2625×4669, even if the phone had a resolution of 1440×2560, is that somehow I put my background image to drawable folder. The drawable folder is same as drawable-mdpi and mdpi stands for 160 DP according to Android.
Motorola Nexus 6 has a density of 560 DP. To match that, Android resized the image multiplying by 560/160 = 3.5
750 x 3.5 = 2625 and
1334 X 3.5 = 4669
2) The reason it was 47 MB is that, even if the image is 160 KB on the disk, Bitmaps are decompressed version of this files and every pixel in ARGB_888 takes 4 Bytes of memory.
2625x4669x4 = 49,024,500 bytes ~ 47 MB
Before explaining the solution always remember to test your application on different devices. That was the main reason I missed that point. The device I tested my app during development cycle had 245 DP and it was hard to notice memory leak (It was using only 15 MB memory). Android documentation has a section for Supporting Different Screen Sizes, but it doesn’t mention that upper-scaling of images can cause high memory usage. It would be nice to see that in the documentation.
The solution to that is putting a single image to drawable-nodpi folder or creating images at different resolutions for different densities. To understand the difference between these options you can check CommonsWare‘s article.
To create images for different densities remember to scale your images according to 3:4:6:8:12:16 ratio.
After fixing this issue, the memory usage on Motorola Nexus 6 dropped to 29 MB.